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>
This commit is contained in:
Родитель
44b8bd7edd
Коммит
e015640f9c
|
@ -1515,7 +1515,9 @@ int btrfs_lookup_file_extent(struct btrfs_trans_handle *trans,
|
||||||
u64 bytenr, int mod);
|
u64 bytenr, int mod);
|
||||||
int btrfs_csum_file_blocks(struct btrfs_trans_handle *trans,
|
int btrfs_csum_file_blocks(struct btrfs_trans_handle *trans,
|
||||||
struct btrfs_root *root, struct inode *inode,
|
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_csum_item *btrfs_lookup_csum(struct btrfs_trans_handle *trans,
|
||||||
struct btrfs_root *root,
|
struct btrfs_root *root,
|
||||||
struct btrfs_path *path,
|
struct btrfs_path *path,
|
||||||
|
|
|
@ -134,9 +134,36 @@ int btrfs_lookup_file_extent(struct btrfs_trans_handle *trans,
|
||||||
return ret;
|
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,
|
int btrfs_csum_file_blocks(struct btrfs_trans_handle *trans,
|
||||||
struct btrfs_root *root, struct inode *inode,
|
struct btrfs_root *root, struct inode *inode,
|
||||||
struct bio *bio)
|
struct bio *bio, char *sums)
|
||||||
{
|
{
|
||||||
u64 objectid = inode->i_ino;
|
u64 objectid = inode->i_ino;
|
||||||
u64 offset;
|
u64 offset;
|
||||||
|
@ -150,12 +177,11 @@ int btrfs_csum_file_blocks(struct btrfs_trans_handle *trans,
|
||||||
struct btrfs_csum_item *item_end;
|
struct btrfs_csum_item *item_end;
|
||||||
struct extent_buffer *leaf = NULL;
|
struct extent_buffer *leaf = NULL;
|
||||||
u64 csum_offset;
|
u64 csum_offset;
|
||||||
u32 csum_result;
|
u32 *sums32 = (u32 *)sums;
|
||||||
u32 nritems;
|
u32 nritems;
|
||||||
u32 ins_size;
|
u32 ins_size;
|
||||||
int bio_index = 0;
|
int bio_index = 0;
|
||||||
struct bio_vec *bvec = bio->bi_io_vec;
|
struct bio_vec *bvec = bio->bi_io_vec;
|
||||||
char *data;
|
|
||||||
char *eb_map;
|
char *eb_map;
|
||||||
char *eb_token;
|
char *eb_token;
|
||||||
unsigned long map_len;
|
unsigned long map_len;
|
||||||
|
@ -278,15 +304,6 @@ found:
|
||||||
btrfs_item_size_nr(leaf, path->slots[0]));
|
btrfs_item_size_nr(leaf, path->slots[0]));
|
||||||
eb_token = NULL;
|
eb_token = NULL;
|
||||||
next_bvec:
|
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 ||
|
if (!eb_token ||
|
||||||
(unsigned long)item + BTRFS_CRC32_SIZE >= map_start + map_len) {
|
(unsigned long)item + BTRFS_CRC32_SIZE >= map_start + map_len) {
|
||||||
|
@ -304,13 +321,14 @@ next_bvec:
|
||||||
}
|
}
|
||||||
if (eb_token) {
|
if (eb_token) {
|
||||||
memcpy(eb_token + ((unsigned long)item & (PAGE_CACHE_SIZE - 1)),
|
memcpy(eb_token + ((unsigned long)item & (PAGE_CACHE_SIZE - 1)),
|
||||||
&csum_result, BTRFS_CRC32_SIZE);
|
sums32, BTRFS_CRC32_SIZE);
|
||||||
} else {
|
} else {
|
||||||
write_extent_buffer(leaf, &csum_result, (unsigned long)item,
|
write_extent_buffer(leaf, sums32, (unsigned long)item,
|
||||||
BTRFS_CRC32_SIZE);
|
BTRFS_CRC32_SIZE);
|
||||||
}
|
}
|
||||||
bio_index++;
|
bio_index++;
|
||||||
bvec++;
|
bvec++;
|
||||||
|
sums32++;
|
||||||
if (bio_index < bio->bi_vcnt) {
|
if (bio_index < bio->bi_vcnt) {
|
||||||
item = (struct btrfs_csum_item *)((char *)item +
|
item = (struct btrfs_csum_item *)((char *)item +
|
||||||
BTRFS_CRC32_SIZE);
|
BTRFS_CRC32_SIZE);
|
||||||
|
|
|
@ -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_root *root = BTRFS_I(inode)->root;
|
||||||
struct btrfs_trans_handle *trans;
|
struct btrfs_trans_handle *trans;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
char *sums = NULL;
|
||||||
|
|
||||||
|
ret = btrfs_csum_one_bio(root, bio, &sums);
|
||||||
|
BUG_ON(ret);
|
||||||
|
|
||||||
mutex_lock(&root->fs_info->fs_mutex);
|
mutex_lock(&root->fs_info->fs_mutex);
|
||||||
trans = btrfs_start_transaction(root, 1);
|
trans = btrfs_start_transaction(root, 1);
|
||||||
|
|
||||||
btrfs_set_trans_block_group(trans, inode);
|
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);
|
ret = btrfs_end_transaction(trans, root);
|
||||||
BUG_ON(ret);
|
BUG_ON(ret);
|
||||||
mutex_unlock(&root->fs_info->fs_mutex);
|
mutex_unlock(&root->fs_info->fs_mutex);
|
||||||
|
|
||||||
|
kfree(sums);
|
||||||
|
|
||||||
return btrfs_map_bio(root, rw, bio, mirror_num);
|
return btrfs_map_bio(root, rw, bio, mirror_num);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче