Skip to content

Commit

Permalink
Btrfs: Write bio checksumming outside the FS mutex
Browse files Browse the repository at this point in the history
This significantly improves streaming write performance by allowing
concurrency in the data checksumming.

Signed-off-by: Chris Mason <chris.mason@oracle.com>
  • Loading branch information
Chris Mason committed Sep 25, 2008
1 parent 44b8bd7 commit e015640
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 16 deletions.
4 changes: 3 additions & 1 deletion fs/btrfs/ctree.h
Original file line number Diff line number Diff line change
Expand Up @@ -1515,7 +1515,9 @@ int btrfs_lookup_file_extent(struct btrfs_trans_handle *trans,
u64 bytenr, int mod);
int btrfs_csum_file_blocks(struct btrfs_trans_handle *trans,
struct btrfs_root *root, struct inode *inode,
struct bio *bio);
struct bio *bio, char *sums);
int btrfs_csum_one_bio(struct btrfs_root *root,
struct bio *bio, char **sums_ret);
struct btrfs_csum_item *btrfs_lookup_csum(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
struct btrfs_path *path,
Expand Down
46 changes: 32 additions & 14 deletions fs/btrfs/file-item.c
Original file line number Diff line number Diff line change
Expand Up @@ -134,9 +134,36 @@ int btrfs_lookup_file_extent(struct btrfs_trans_handle *trans,
return ret;
}

int btrfs_csum_one_bio(struct btrfs_root *root,
struct bio *bio, char **sums_ret)
{
u32 *sums;
char *data;
struct bio_vec *bvec = bio->bi_io_vec;
int bio_index = 0;

sums = kmalloc(bio->bi_vcnt * BTRFS_CRC32_SIZE, GFP_NOFS);
if (!sums)
return -ENOMEM;
*sums_ret = (char *)sums;

while(bio_index < bio->bi_vcnt) {
data = kmap_atomic(bvec->bv_page, KM_USER0);
*sums = ~(u32)0;
*sums = btrfs_csum_data(root, data + bvec->bv_offset,
*sums, bvec->bv_len);
kunmap_atomic(data, KM_USER0);
btrfs_csum_final(*sums, (char *)sums);
sums++;
bio_index++;
bvec++;
}
return 0;
}

int btrfs_csum_file_blocks(struct btrfs_trans_handle *trans,
struct btrfs_root *root, struct inode *inode,
struct bio *bio)
struct bio *bio, char *sums)
{
u64 objectid = inode->i_ino;
u64 offset;
Expand All @@ -150,12 +177,11 @@ int btrfs_csum_file_blocks(struct btrfs_trans_handle *trans,
struct btrfs_csum_item *item_end;
struct extent_buffer *leaf = NULL;
u64 csum_offset;
u32 csum_result;
u32 *sums32 = (u32 *)sums;
u32 nritems;
u32 ins_size;
int bio_index = 0;
struct bio_vec *bvec = bio->bi_io_vec;
char *data;
char *eb_map;
char *eb_token;
unsigned long map_len;
Expand Down Expand Up @@ -278,15 +304,6 @@ int btrfs_csum_file_blocks(struct btrfs_trans_handle *trans,
btrfs_item_size_nr(leaf, path->slots[0]));
eb_token = NULL;
next_bvec:
data = kmap_atomic(bvec->bv_page, KM_USER0);
csum_result = ~(u32)0;
csum_result = btrfs_csum_data(root, data + bvec->bv_offset,
csum_result, bvec->bv_len);
kunmap_atomic(data, KM_USER0);
btrfs_csum_final(csum_result, (char *)&csum_result);
if (csum_result == 0) {
printk("csum result is 0 for inode %lu offset %Lu\n", inode->i_ino, offset);
}

if (!eb_token ||
(unsigned long)item + BTRFS_CRC32_SIZE >= map_start + map_len) {
Expand All @@ -304,13 +321,14 @@ int btrfs_csum_file_blocks(struct btrfs_trans_handle *trans,
}
if (eb_token) {
memcpy(eb_token + ((unsigned long)item & (PAGE_CACHE_SIZE - 1)),
&csum_result, BTRFS_CRC32_SIZE);
sums32, BTRFS_CRC32_SIZE);
} else {
write_extent_buffer(leaf, &csum_result, (unsigned long)item,
write_extent_buffer(leaf, sums32, (unsigned long)item,
BTRFS_CRC32_SIZE);
}
bio_index++;
bvec++;
sums32++;
if (bio_index < bio->bi_vcnt) {
item = (struct btrfs_csum_item *)((char *)item +
BTRFS_CRC32_SIZE);
Expand Down
11 changes: 10 additions & 1 deletion fs/btrfs/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -330,14 +330,23 @@ int __btrfs_submit_bio_hook(struct inode *inode, int rw, struct bio *bio,
struct btrfs_root *root = BTRFS_I(inode)->root;
struct btrfs_trans_handle *trans;
int ret = 0;
char *sums = NULL;

ret = btrfs_csum_one_bio(root, bio, &sums);
BUG_ON(ret);

mutex_lock(&root->fs_info->fs_mutex);
trans = btrfs_start_transaction(root, 1);

btrfs_set_trans_block_group(trans, inode);
btrfs_csum_file_blocks(trans, root, inode, bio);
btrfs_csum_file_blocks(trans, root, inode, bio, sums);

ret = btrfs_end_transaction(trans, root);
BUG_ON(ret);
mutex_unlock(&root->fs_info->fs_mutex);

kfree(sums);

return btrfs_map_bio(root, rw, bio, mirror_num);
}

Expand Down

0 comments on commit e015640

Please sign in to comment.