diff options
author | Chris Mason <chris.mason@oracle.com> | 2008-04-16 11:15:20 -0400 |
---|---|---|
committer | Chris Mason <chris.mason@oracle.com> | 2008-09-25 11:04:01 -0400 |
commit | e015640f9c4fa2417dcc3bbbb3b2b61ad4059ab0 (patch) | |
tree | 2ba41617e428f60ff970abc8a862ab77980b4a20 | |
parent | 44b8bd7edda4f63de180d0f7325c9fb704b3806b (diff) |
Btrfs: Write bio checksumming outside the FS mutex
This significantly improves streaming write performance by allowing
concurrency in the data checksumming.
Signed-off-by: Chris Mason <chris.mason@oracle.com>
-rw-r--r-- | fs/btrfs/ctree.h | 4 | ||||
-rw-r--r-- | fs/btrfs/file-item.c | 46 | ||||
-rw-r--r-- | fs/btrfs/inode.c | 11 |
3 files changed, 45 insertions, 16 deletions
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index ff15b8513f90..b56ae1950658 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h | |||
@@ -1515,7 +1515,9 @@ int btrfs_lookup_file_extent(struct btrfs_trans_handle *trans, | |||
1515 | u64 bytenr, int mod); | 1515 | u64 bytenr, int mod); |
1516 | int btrfs_csum_file_blocks(struct btrfs_trans_handle *trans, | 1516 | int btrfs_csum_file_blocks(struct btrfs_trans_handle *trans, |
1517 | struct btrfs_root *root, struct inode *inode, | 1517 | struct btrfs_root *root, struct inode *inode, |
1518 | struct bio *bio); | 1518 | struct bio *bio, char *sums); |
1519 | int btrfs_csum_one_bio(struct btrfs_root *root, | ||
1520 | struct bio *bio, char **sums_ret); | ||
1519 | struct btrfs_csum_item *btrfs_lookup_csum(struct btrfs_trans_handle *trans, | 1521 | struct btrfs_csum_item *btrfs_lookup_csum(struct btrfs_trans_handle *trans, |
1520 | struct btrfs_root *root, | 1522 | struct btrfs_root *root, |
1521 | struct btrfs_path *path, | 1523 | struct btrfs_path *path, |
diff --git a/fs/btrfs/file-item.c b/fs/btrfs/file-item.c index 374d0245b29d..9259aece6ed1 100644 --- a/fs/btrfs/file-item.c +++ b/fs/btrfs/file-item.c | |||
@@ -134,9 +134,36 @@ int btrfs_lookup_file_extent(struct btrfs_trans_handle *trans, | |||
134 | return ret; | 134 | return ret; |
135 | } | 135 | } |
136 | 136 | ||
137 | int btrfs_csum_one_bio(struct btrfs_root *root, | ||
138 | struct bio *bio, char **sums_ret) | ||
139 | { | ||
140 | u32 *sums; | ||
141 | char *data; | ||
142 | struct bio_vec *bvec = bio->bi_io_vec; | ||
143 | int bio_index = 0; | ||
144 | |||
145 | sums = kmalloc(bio->bi_vcnt * BTRFS_CRC32_SIZE, GFP_NOFS); | ||
146 | if (!sums) | ||
147 | return -ENOMEM; | ||
148 | *sums_ret = (char *)sums; | ||
149 | |||
150 | while(bio_index < bio->bi_vcnt) { | ||
151 | data = kmap_atomic(bvec->bv_page, KM_USER0); | ||
152 | *sums = ~(u32)0; | ||
153 | *sums = btrfs_csum_data(root, data + bvec->bv_offset, | ||
154 | *sums, bvec->bv_len); | ||
155 | kunmap_atomic(data, KM_USER0); | ||
156 | btrfs_csum_final(*sums, (char *)sums); | ||
157 | sums++; | ||
158 | bio_index++; | ||
159 | bvec++; | ||
160 | } | ||
161 | return 0; | ||
162 | } | ||
163 | |||
137 | int btrfs_csum_file_blocks(struct btrfs_trans_handle *trans, | 164 | int btrfs_csum_file_blocks(struct btrfs_trans_handle *trans, |
138 | struct btrfs_root *root, struct inode *inode, | 165 | struct btrfs_root *root, struct inode *inode, |
139 | struct bio *bio) | 166 | struct bio *bio, char *sums) |
140 | { | 167 | { |
141 | u64 objectid = inode->i_ino; | 168 | u64 objectid = inode->i_ino; |
142 | u64 offset; | 169 | u64 offset; |
@@ -150,12 +177,11 @@ int btrfs_csum_file_blocks(struct btrfs_trans_handle *trans, | |||
150 | struct btrfs_csum_item *item_end; | 177 | struct btrfs_csum_item *item_end; |
151 | struct extent_buffer *leaf = NULL; | 178 | struct extent_buffer *leaf = NULL; |
152 | u64 csum_offset; | 179 | u64 csum_offset; |
153 | u32 csum_result; | 180 | u32 *sums32 = (u32 *)sums; |
154 | u32 nritems; | 181 | u32 nritems; |
155 | u32 ins_size; | 182 | u32 ins_size; |
156 | int bio_index = 0; | 183 | int bio_index = 0; |
157 | struct bio_vec *bvec = bio->bi_io_vec; | 184 | struct bio_vec *bvec = bio->bi_io_vec; |
158 | char *data; | ||
159 | char *eb_map; | 185 | char *eb_map; |
160 | char *eb_token; | 186 | char *eb_token; |
161 | unsigned long map_len; | 187 | unsigned long map_len; |
@@ -278,15 +304,6 @@ found: | |||
278 | btrfs_item_size_nr(leaf, path->slots[0])); | 304 | btrfs_item_size_nr(leaf, path->slots[0])); |
279 | eb_token = NULL; | 305 | eb_token = NULL; |
280 | next_bvec: | 306 | next_bvec: |
281 | data = kmap_atomic(bvec->bv_page, KM_USER0); | ||
282 | csum_result = ~(u32)0; | ||
283 | csum_result = btrfs_csum_data(root, data + bvec->bv_offset, | ||
284 | csum_result, bvec->bv_len); | ||
285 | kunmap_atomic(data, KM_USER0); | ||
286 | btrfs_csum_final(csum_result, (char *)&csum_result); | ||
287 | if (csum_result == 0) { | ||
288 | printk("csum result is 0 for inode %lu offset %Lu\n", inode->i_ino, offset); | ||
289 | } | ||
290 | 307 | ||
291 | if (!eb_token || | 308 | if (!eb_token || |
292 | (unsigned long)item + BTRFS_CRC32_SIZE >= map_start + map_len) { | 309 | (unsigned long)item + BTRFS_CRC32_SIZE >= map_start + map_len) { |
@@ -304,13 +321,14 @@ next_bvec: | |||
304 | } | 321 | } |
305 | if (eb_token) { | 322 | if (eb_token) { |
306 | memcpy(eb_token + ((unsigned long)item & (PAGE_CACHE_SIZE - 1)), | 323 | memcpy(eb_token + ((unsigned long)item & (PAGE_CACHE_SIZE - 1)), |
307 | &csum_result, BTRFS_CRC32_SIZE); | 324 | sums32, BTRFS_CRC32_SIZE); |
308 | } else { | 325 | } else { |
309 | write_extent_buffer(leaf, &csum_result, (unsigned long)item, | 326 | write_extent_buffer(leaf, sums32, (unsigned long)item, |
310 | BTRFS_CRC32_SIZE); | 327 | BTRFS_CRC32_SIZE); |
311 | } | 328 | } |
312 | bio_index++; | 329 | bio_index++; |
313 | bvec++; | 330 | bvec++; |
331 | sums32++; | ||
314 | if (bio_index < bio->bi_vcnt) { | 332 | if (bio_index < bio->bi_vcnt) { |
315 | item = (struct btrfs_csum_item *)((char *)item + | 333 | item = (struct btrfs_csum_item *)((char *)item + |
316 | BTRFS_CRC32_SIZE); | 334 | BTRFS_CRC32_SIZE); |
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 457daf725d29..3e1f21c632c1 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c | |||
@@ -330,14 +330,23 @@ int __btrfs_submit_bio_hook(struct inode *inode, int rw, struct bio *bio, | |||
330 | struct btrfs_root *root = BTRFS_I(inode)->root; | 330 | struct btrfs_root *root = BTRFS_I(inode)->root; |
331 | struct btrfs_trans_handle *trans; | 331 | struct btrfs_trans_handle *trans; |
332 | int ret = 0; | 332 | int ret = 0; |
333 | char *sums = NULL; | ||
334 | |||
335 | ret = btrfs_csum_one_bio(root, bio, &sums); | ||
336 | BUG_ON(ret); | ||
333 | 337 | ||
334 | mutex_lock(&root->fs_info->fs_mutex); | 338 | mutex_lock(&root->fs_info->fs_mutex); |
335 | trans = btrfs_start_transaction(root, 1); | 339 | trans = btrfs_start_transaction(root, 1); |
340 | |||
336 | btrfs_set_trans_block_group(trans, inode); | 341 | btrfs_set_trans_block_group(trans, inode); |
337 | btrfs_csum_file_blocks(trans, root, inode, bio); | 342 | btrfs_csum_file_blocks(trans, root, inode, bio, sums); |
343 | |||
338 | ret = btrfs_end_transaction(trans, root); | 344 | ret = btrfs_end_transaction(trans, root); |
339 | BUG_ON(ret); | 345 | BUG_ON(ret); |
340 | mutex_unlock(&root->fs_info->fs_mutex); | 346 | mutex_unlock(&root->fs_info->fs_mutex); |
347 | |||
348 | kfree(sums); | ||
349 | |||
341 | return btrfs_map_bio(root, rw, bio, mirror_num); | 350 | return btrfs_map_bio(root, rw, bio, mirror_num); |
342 | } | 351 | } |
343 | 352 | ||