aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorMiao Xie <miaox@cn.fujitsu.com>2013-04-05 03:20:56 -0400
committerJosef Bacik <jbacik@fusionio.com>2013-05-06 15:54:35 -0400
commite4100d987b2437596ebcf11809022b79507f3db1 (patch)
tree2e1b987afa41149ef621581f1eb125c027453f74 /fs
parent09a2a8f96e3009273bed1833b3f210e2c68728a5 (diff)
Btrfs: improve the performance of the csums lookup
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 Signed-off-by: Miao Xie <miaox@cn.fujitsu.com> Signed-off-by: Josef Bacik <jbacik@fusionio.com>
Diffstat (limited to 'fs')
-rw-r--r--fs/btrfs/extent_io.c58
-rw-r--r--fs/btrfs/extent_io.h4
-rw-r--r--fs/btrfs/file-item.c49
-rw-r--r--fs/btrfs/ordered-data.c28
-rw-r--r--fs/btrfs/ordered-data.h3
5 files changed, 111 insertions, 31 deletions
diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c
index 1e4627c33548..617b5779b95b 100644
--- a/fs/btrfs/extent_io.c
+++ b/fs/btrfs/extent_io.c
@@ -1777,6 +1777,64 @@ out:
1777 return ret; 1777 return ret;
1778} 1778}
1779 1779
1780void extent_cache_csums_dio(struct extent_io_tree *tree, u64 start, u32 csums[],
1781 int count)
1782{
1783 struct rb_node *node;
1784 struct extent_state *state;
1785
1786 spin_lock(&tree->lock);
1787 /*
1788 * this search will find all the extents that end after
1789 * our range starts.
1790 */
1791 node = tree_search(tree, start);
1792 BUG_ON(!node);
1793
1794 state = rb_entry(node, struct extent_state, rb_node);
1795 BUG_ON(state->start != start);
1796
1797 while (count) {
1798 state->private = *csums++;
1799 count--;
1800 state = next_state(state);
1801 }
1802 spin_unlock(&tree->lock);
1803}
1804
1805static inline u64 __btrfs_get_bio_offset(struct bio *bio, int bio_index)
1806{
1807 struct bio_vec *bvec = bio->bi_io_vec + bio_index;
1808
1809 return page_offset(bvec->bv_page) + bvec->bv_offset;
1810}
1811
1812void extent_cache_csums(struct extent_io_tree *tree, struct bio *bio, int bio_index,
1813 u32 csums[], int count)
1814{
1815 struct rb_node *node;
1816 struct extent_state *state = NULL;
1817 u64 start;
1818
1819 spin_lock(&tree->lock);
1820 do {
1821 start = __btrfs_get_bio_offset(bio, bio_index);
1822 if (state == NULL || state->start != start) {
1823 node = tree_search(tree, start);
1824 BUG_ON(!node);
1825
1826 state = rb_entry(node, struct extent_state, rb_node);
1827 BUG_ON(state->start != start);
1828 }
1829 state->private = *csums++;
1830 count--;
1831 bio_index++;
1832
1833 state = next_state(state);
1834 } while (count);
1835 spin_unlock(&tree->lock);
1836}
1837
1780int get_state_private(struct extent_io_tree *tree, u64 start, u64 *private) 1838int get_state_private(struct extent_io_tree *tree, u64 start, u64 *private)
1781{ 1839{
1782 struct rb_node *node; 1840 struct rb_node *node;
diff --git a/fs/btrfs/extent_io.h b/fs/btrfs/extent_io.h
index 258c92156857..db009d80bef4 100644
--- a/fs/btrfs/extent_io.h
+++ b/fs/btrfs/extent_io.h
@@ -261,6 +261,10 @@ int extent_readpages(struct extent_io_tree *tree,
261int extent_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, 261int extent_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
262 __u64 start, __u64 len, get_extent_t *get_extent); 262 __u64 start, __u64 len, get_extent_t *get_extent);
263int set_state_private(struct extent_io_tree *tree, u64 start, u64 private); 263int set_state_private(struct extent_io_tree *tree, u64 start, u64 private);
264void extent_cache_csums_dio(struct extent_io_tree *tree, u64 start, u32 csums[],
265 int count);
266void extent_cache_csums(struct extent_io_tree *tree, struct bio *bio,
267 int bvec_index, u32 csums[], int count);
264int get_state_private(struct extent_io_tree *tree, u64 start, u64 *private); 268int get_state_private(struct extent_io_tree *tree, u64 start, u64 *private);
265void set_page_extent_mapped(struct page *page); 269void set_page_extent_mapped(struct page *page);
266 270
diff --git a/fs/btrfs/file-item.c b/fs/btrfs/file-item.c
index ad3cd8614d29..18f12aab6ebf 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,
177 struct inode *inode, struct bio *bio, 177 struct inode *inode, struct bio *bio,
178 u64 logical_offset, u32 *dst, int dio) 178 u64 logical_offset, u32 *dst, int dio)
179{ 179{
180 u32 sum; 180 u32 sum[16];
181 int len;
181 struct bio_vec *bvec = bio->bi_io_vec; 182 struct bio_vec *bvec = bio->bi_io_vec;
182 int bio_index = 0; 183 int bio_index = 0;
183 u64 offset = 0; 184 u64 offset = 0;
@@ -186,7 +187,7 @@ static int __btrfs_lookup_bio_sums(struct btrfs_root *root,
186 u64 disk_bytenr; 187 u64 disk_bytenr;
187 u32 diff; 188 u32 diff;
188 u16 csum_size = btrfs_super_csum_size(root->fs_info->super_copy); 189 u16 csum_size = btrfs_super_csum_size(root->fs_info->super_copy);
189 int ret; 190 int count;
190 struct btrfs_path *path; 191 struct btrfs_path *path;
191 struct btrfs_csum_item *item = NULL; 192 struct btrfs_csum_item *item = NULL;
192 struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree; 193 struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree;
@@ -214,10 +215,12 @@ static int __btrfs_lookup_bio_sums(struct btrfs_root *root,
214 if (dio) 215 if (dio)
215 offset = logical_offset; 216 offset = logical_offset;
216 while (bio_index < bio->bi_vcnt) { 217 while (bio_index < bio->bi_vcnt) {
218 len = min_t(int, ARRAY_SIZE(sum), bio->bi_vcnt - bio_index);
217 if (!dio) 219 if (!dio)
218 offset = page_offset(bvec->bv_page) + bvec->bv_offset; 220 offset = page_offset(bvec->bv_page) + bvec->bv_offset;
219 ret = btrfs_find_ordered_sum(inode, offset, disk_bytenr, &sum); 221 count = btrfs_find_ordered_sum(inode, offset, disk_bytenr, sum,
220 if (ret == 0) 222 len);
223 if (count)
221 goto found; 224 goto found;
222 225
223 if (!item || disk_bytenr < item_start_offset || 226 if (!item || disk_bytenr < item_start_offset ||
@@ -230,10 +233,8 @@ static int __btrfs_lookup_bio_sums(struct btrfs_root *root,
230 item = btrfs_lookup_csum(NULL, root->fs_info->csum_root, 233 item = btrfs_lookup_csum(NULL, root->fs_info->csum_root,
231 path, disk_bytenr, 0); 234 path, disk_bytenr, 0);
232 if (IS_ERR(item)) { 235 if (IS_ERR(item)) {
233 ret = PTR_ERR(item); 236 count = 1;
234 if (ret == -ENOENT || ret == -EFBIG) 237 sum[0] = 0;
235 ret = 0;
236 sum = 0;
237 if (BTRFS_I(inode)->root->root_key.objectid == 238 if (BTRFS_I(inode)->root->root_key.objectid ==
238 BTRFS_DATA_RELOC_TREE_OBJECTID) { 239 BTRFS_DATA_RELOC_TREE_OBJECTID) {
239 set_extent_bits(io_tree, offset, 240 set_extent_bits(io_tree, offset,
@@ -269,19 +270,29 @@ static int __btrfs_lookup_bio_sums(struct btrfs_root *root,
269 diff = disk_bytenr - item_start_offset; 270 diff = disk_bytenr - item_start_offset;
270 diff = diff / root->sectorsize; 271 diff = diff / root->sectorsize;
271 diff = diff * csum_size; 272 diff = diff * csum_size;
272 273 count = min_t(int, len, (item_last_offset - disk_bytenr) >>
273 read_extent_buffer(path->nodes[0], &sum, 274 inode->i_sb->s_blocksize_bits);
275 read_extent_buffer(path->nodes[0], sum,
274 ((unsigned long)item) + diff, 276 ((unsigned long)item) + diff,
275 csum_size); 277 csum_size * count);
276found: 278found:
277 if (dst) 279 if (dst) {
278 *dst++ = sum; 280 memcpy(dst, sum, count * csum_size);
279 else 281 dst += count;
280 set_state_private(io_tree, offset, sum); 282 } else {
281 disk_bytenr += bvec->bv_len; 283 if (dio)
282 offset += bvec->bv_len; 284 extent_cache_csums_dio(io_tree, offset, sum,
283 bio_index++; 285 count);
284 bvec++; 286 else
287 extent_cache_csums(io_tree, bio, bio_index, sum,
288 count);
289 }
290 while (count--) {
291 disk_bytenr += bvec->bv_len;
292 offset += bvec->bv_len;
293 bio_index++;
294 bvec++;
295 }
285 } 296 }
286 btrfs_free_path(path); 297 btrfs_free_path(path);
287 return 0; 298 return 0;
diff --git a/fs/btrfs/ordered-data.c b/fs/btrfs/ordered-data.c
index 005c45db699e..1ddd728541ee 100644
--- a/fs/btrfs/ordered-data.c
+++ b/fs/btrfs/ordered-data.c
@@ -986,7 +986,7 @@ out:
986 * be reclaimed before their checksum is actually put into the btree 986 * be reclaimed before their checksum is actually put into the btree
987 */ 987 */
988int btrfs_find_ordered_sum(struct inode *inode, u64 offset, u64 disk_bytenr, 988int btrfs_find_ordered_sum(struct inode *inode, u64 offset, u64 disk_bytenr,
989 u32 *sum) 989 u32 *sum, int len)
990{ 990{
991 struct btrfs_ordered_sum *ordered_sum; 991 struct btrfs_ordered_sum *ordered_sum;
992 struct btrfs_sector_sum *sector_sums; 992 struct btrfs_sector_sum *sector_sums;
@@ -995,22 +995,28 @@ int btrfs_find_ordered_sum(struct inode *inode, u64 offset, u64 disk_bytenr,
995 unsigned long num_sectors; 995 unsigned long num_sectors;
996 unsigned long i; 996 unsigned long i;
997 u32 sectorsize = BTRFS_I(inode)->root->sectorsize; 997 u32 sectorsize = BTRFS_I(inode)->root->sectorsize;
998 int ret = 1; 998 int index = 0;
999 999
1000 ordered = btrfs_lookup_ordered_extent(inode, offset); 1000 ordered = btrfs_lookup_ordered_extent(inode, offset);
1001 if (!ordered) 1001 if (!ordered)
1002 return 1; 1002 return 0;
1003 1003
1004 spin_lock_irq(&tree->lock); 1004 spin_lock_irq(&tree->lock);
1005 list_for_each_entry_reverse(ordered_sum, &ordered->list, list) { 1005 list_for_each_entry_reverse(ordered_sum, &ordered->list, list) {
1006 if (disk_bytenr >= ordered_sum->bytenr) { 1006 if (disk_bytenr >= ordered_sum->bytenr &&
1007 num_sectors = ordered_sum->len / sectorsize; 1007 disk_bytenr < ordered_sum->bytenr + ordered_sum->len) {
1008 sector_sums = ordered_sum->sums; 1008 i = (disk_bytenr - ordered_sum->bytenr) >>
1009 for (i = 0; i < num_sectors; i++) { 1009 inode->i_sb->s_blocksize_bits;
1010 sector_sums = ordered_sum->sums + i;
1011 num_sectors = ordered_sum->len >>
1012 inode->i_sb->s_blocksize_bits;
1013 for (; i < num_sectors; i++) {
1010 if (sector_sums[i].bytenr == disk_bytenr) { 1014 if (sector_sums[i].bytenr == disk_bytenr) {
1011 *sum = sector_sums[i].sum; 1015 sum[index] = sector_sums[i].sum;
1012 ret = 0; 1016 index++;
1013 goto out; 1017 if (index == len)
1018 goto out;
1019 disk_bytenr += sectorsize;
1014 } 1020 }
1015 } 1021 }
1016 } 1022 }
@@ -1018,7 +1024,7 @@ int btrfs_find_ordered_sum(struct inode *inode, u64 offset, u64 disk_bytenr,
1018out: 1024out:
1019 spin_unlock_irq(&tree->lock); 1025 spin_unlock_irq(&tree->lock);
1020 btrfs_put_ordered_extent(ordered); 1026 btrfs_put_ordered_extent(ordered);
1021 return ret; 1027 return index;
1022} 1028}
1023 1029
1024 1030
diff --git a/fs/btrfs/ordered-data.h b/fs/btrfs/ordered-data.h
index 8eadfe406cdd..58b0e3b0ebad 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,
196 u64 len); 196 u64 len);
197int btrfs_ordered_update_i_size(struct inode *inode, u64 offset, 197int btrfs_ordered_update_i_size(struct inode *inode, u64 offset,
198 struct btrfs_ordered_extent *ordered); 198 struct btrfs_ordered_extent *ordered);
199int btrfs_find_ordered_sum(struct inode *inode, u64 offset, u64 disk_bytenr, u32 *sum); 199int btrfs_find_ordered_sum(struct inode *inode, u64 offset, u64 disk_bytenr,
200 u32 *sum, int len);
200int btrfs_run_ordered_operations(struct btrfs_trans_handle *trans, 201int btrfs_run_ordered_operations(struct btrfs_trans_handle *trans,
201 struct btrfs_root *root, int wait); 202 struct btrfs_root *root, int wait);
202void btrfs_add_ordered_operation(struct btrfs_trans_handle *trans, 203void btrfs_add_ordered_operation(struct btrfs_trans_handle *trans,