mirror of
https://github.com/adulau/aha.git
synced 2024-12-29 04:06:22 +00:00
Btrfs: Handle data checksumming on bios that span multiple ordered extents
Data checksumming is done right before the bio is sent down the IO stack, which means a single bio might span more than one ordered extent. In this case, the checksumming data is split between two ordered extents. Signed-off-by: Chris Mason <chris.mason@oracle.com>
This commit is contained in:
parent
eb84ae039e
commit
3edf7d33f4
5 changed files with 69 additions and 31 deletions
|
@ -1579,8 +1579,8 @@ int btrfs_lookup_file_extent(struct btrfs_trans_handle *trans,
|
||||||
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 btrfs_ordered_sum *sums);
|
struct btrfs_ordered_sum *sums);
|
||||||
int btrfs_csum_one_bio(struct btrfs_root *root,
|
int btrfs_csum_one_bio(struct btrfs_root *root, struct inode *inode,
|
||||||
struct bio *bio, struct btrfs_ordered_sum **sums_ret);
|
struct bio *bio);
|
||||||
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,26 +134,53 @@ int btrfs_lookup_file_extent(struct btrfs_trans_handle *trans,
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int btrfs_csum_one_bio(struct btrfs_root *root,
|
int btrfs_csum_one_bio(struct btrfs_root *root, struct inode *inode,
|
||||||
struct bio *bio, struct btrfs_ordered_sum **sums_ret)
|
struct bio *bio)
|
||||||
{
|
{
|
||||||
struct btrfs_ordered_sum *sums;
|
struct btrfs_ordered_sum *sums;
|
||||||
struct btrfs_sector_sum *sector_sum;
|
struct btrfs_sector_sum *sector_sum;
|
||||||
|
struct btrfs_ordered_extent *ordered;
|
||||||
char *data;
|
char *data;
|
||||||
struct bio_vec *bvec = bio->bi_io_vec;
|
struct bio_vec *bvec = bio->bi_io_vec;
|
||||||
int bio_index = 0;
|
int bio_index = 0;
|
||||||
|
unsigned long total_bytes = 0;
|
||||||
|
unsigned long this_sum_bytes = 0;
|
||||||
|
u64 offset;
|
||||||
|
|
||||||
WARN_ON(bio->bi_vcnt <= 0);
|
WARN_ON(bio->bi_vcnt <= 0);
|
||||||
sums = kzalloc(btrfs_ordered_sum_size(root, bio->bi_size), GFP_NOFS);
|
sums = kzalloc(btrfs_ordered_sum_size(root, bio->bi_size), GFP_NOFS);
|
||||||
if (!sums)
|
if (!sums)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
*sums_ret = sums;
|
|
||||||
sector_sum = &sums->sums;
|
sector_sum = &sums->sums;
|
||||||
sums->file_offset = page_offset(bvec->bv_page);
|
sums->file_offset = page_offset(bvec->bv_page) + bvec->bv_offset;
|
||||||
sums->len = bio->bi_size;
|
sums->len = bio->bi_size;
|
||||||
INIT_LIST_HEAD(&sums->list);
|
INIT_LIST_HEAD(&sums->list);
|
||||||
|
ordered = btrfs_lookup_ordered_extent(inode, sums->file_offset);
|
||||||
|
BUG_ON(!ordered);
|
||||||
|
|
||||||
while(bio_index < bio->bi_vcnt) {
|
while(bio_index < bio->bi_vcnt) {
|
||||||
|
offset = page_offset(bvec->bv_page) + bvec->bv_offset;
|
||||||
|
if (offset >= ordered->file_offset + ordered->len) {
|
||||||
|
unsigned long bytes_left;
|
||||||
|
sums->len = this_sum_bytes;
|
||||||
|
this_sum_bytes = 0;
|
||||||
|
btrfs_add_ordered_sum(inode, ordered, sums);
|
||||||
|
btrfs_put_ordered_extent(ordered);
|
||||||
|
|
||||||
|
bytes_left = bio->bi_size - total_bytes;
|
||||||
|
|
||||||
|
sums = kzalloc(btrfs_ordered_sum_size(root, bytes_left),
|
||||||
|
GFP_NOFS);
|
||||||
|
BUG_ON(!sums);
|
||||||
|
sector_sum = &sums->sums;
|
||||||
|
sums->len = bytes_left;
|
||||||
|
sums->file_offset = offset;
|
||||||
|
ordered = btrfs_lookup_ordered_extent(inode,
|
||||||
|
sums->file_offset);
|
||||||
|
BUG_ON(!ordered);
|
||||||
|
}
|
||||||
|
|
||||||
data = kmap_atomic(bvec->bv_page, KM_USER0);
|
data = kmap_atomic(bvec->bv_page, KM_USER0);
|
||||||
sector_sum->sum = ~(u32)0;
|
sector_sum->sum = ~(u32)0;
|
||||||
sector_sum->sum = btrfs_csum_data(root,
|
sector_sum->sum = btrfs_csum_data(root,
|
||||||
|
@ -165,10 +192,18 @@ int btrfs_csum_one_bio(struct btrfs_root *root,
|
||||||
(char *)§or_sum->sum);
|
(char *)§or_sum->sum);
|
||||||
sector_sum->offset = page_offset(bvec->bv_page) +
|
sector_sum->offset = page_offset(bvec->bv_page) +
|
||||||
bvec->bv_offset;
|
bvec->bv_offset;
|
||||||
|
|
||||||
sector_sum++;
|
sector_sum++;
|
||||||
bio_index++;
|
bio_index++;
|
||||||
|
total_bytes += bvec->bv_len;
|
||||||
|
this_sum_bytes += bvec->bv_len;
|
||||||
bvec++;
|
bvec++;
|
||||||
}
|
}
|
||||||
|
btrfs_add_ordered_sum(inode, ordered, sums);
|
||||||
|
btrfs_put_ordered_extent(ordered);
|
||||||
|
if (total_bytes != bio->bi_size) {
|
||||||
|
printk("warning, total bytes %lu bio size %u\n", total_bytes, bio->bi_size);
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -351,12 +351,8 @@ 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;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
struct btrfs_ordered_sum *sums;
|
|
||||||
|
|
||||||
ret = btrfs_csum_one_bio(root, bio, &sums);
|
ret = btrfs_csum_one_bio(root, inode, bio);
|
||||||
BUG_ON(ret);
|
|
||||||
|
|
||||||
ret = btrfs_add_ordered_sum(inode, sums);
|
|
||||||
BUG_ON(ret);
|
BUG_ON(ret);
|
||||||
|
|
||||||
return btrfs_map_bio(root, rw, bio, mirror_num, 1);
|
return btrfs_map_bio(root, rw, bio, mirror_num, 1);
|
||||||
|
|
|
@ -186,22 +186,17 @@ int btrfs_add_ordered_extent(struct inode *inode, u64 file_offset,
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Add a struct btrfs_ordered_sum into the list of checksums to be inserted
|
* Add a struct btrfs_ordered_sum into the list of checksums to be inserted
|
||||||
* when an ordered extent is finished.
|
* when an ordered extent is finished. If the list covers more than one
|
||||||
|
* ordered extent, it is split across multiples.
|
||||||
*/
|
*/
|
||||||
int btrfs_add_ordered_sum(struct inode *inode, struct btrfs_ordered_sum *sum)
|
int btrfs_add_ordered_sum(struct inode *inode,
|
||||||
|
struct btrfs_ordered_extent *entry,
|
||||||
|
struct btrfs_ordered_sum *sum)
|
||||||
{
|
{
|
||||||
struct btrfs_ordered_inode_tree *tree;
|
struct btrfs_ordered_inode_tree *tree;
|
||||||
struct rb_node *node;
|
|
||||||
struct btrfs_ordered_extent *entry;
|
|
||||||
|
|
||||||
tree = &BTRFS_I(inode)->ordered_tree;
|
tree = &BTRFS_I(inode)->ordered_tree;
|
||||||
mutex_lock(&tree->mutex);
|
mutex_lock(&tree->mutex);
|
||||||
node = tree_search(tree, sum->file_offset);
|
|
||||||
BUG_ON(!node);
|
|
||||||
|
|
||||||
entry = rb_entry(node, struct btrfs_ordered_extent, rb_node);
|
|
||||||
BUG_ON(!offset_in_entry(entry, sum->file_offset));
|
|
||||||
|
|
||||||
list_add_tail(&sum->list, &entry->list);
|
list_add_tail(&sum->list, &entry->list);
|
||||||
mutex_unlock(&tree->mutex);
|
mutex_unlock(&tree->mutex);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -524,8 +519,10 @@ int btrfs_find_ordered_sum(struct inode *inode, u64 offset, u32 *sum)
|
||||||
struct btrfs_ordered_extent *ordered;
|
struct btrfs_ordered_extent *ordered;
|
||||||
struct btrfs_ordered_inode_tree *tree = &BTRFS_I(inode)->ordered_tree;
|
struct btrfs_ordered_inode_tree *tree = &BTRFS_I(inode)->ordered_tree;
|
||||||
struct list_head *cur;
|
struct list_head *cur;
|
||||||
|
unsigned long num_sectors;
|
||||||
|
unsigned long i;
|
||||||
|
u32 sectorsize = BTRFS_I(inode)->root->sectorsize;
|
||||||
int ret = 1;
|
int ret = 1;
|
||||||
int index;
|
|
||||||
|
|
||||||
ordered = btrfs_lookup_ordered_extent(inode, offset);
|
ordered = btrfs_lookup_ordered_extent(inode, offset);
|
||||||
if (!ordered)
|
if (!ordered)
|
||||||
|
@ -534,14 +531,17 @@ int btrfs_find_ordered_sum(struct inode *inode, u64 offset, u32 *sum)
|
||||||
mutex_lock(&tree->mutex);
|
mutex_lock(&tree->mutex);
|
||||||
list_for_each_prev(cur, &ordered->list) {
|
list_for_each_prev(cur, &ordered->list) {
|
||||||
ordered_sum = list_entry(cur, struct btrfs_ordered_sum, list);
|
ordered_sum = list_entry(cur, struct btrfs_ordered_sum, list);
|
||||||
if (offset >= ordered_sum->file_offset &&
|
if (offset >= ordered_sum->file_offset) {
|
||||||
offset < ordered_sum->file_offset + ordered_sum->len) {
|
num_sectors = ordered_sum->len / sectorsize;
|
||||||
index = (offset - ordered_sum->file_offset) /
|
|
||||||
BTRFS_I(inode)->root->sectorsize;;
|
|
||||||
sector_sums = &ordered_sum->sums;
|
sector_sums = &ordered_sum->sums;
|
||||||
*sum = sector_sums[index].sum;
|
for (i = 0; i < num_sectors; i++) {
|
||||||
ret = 0;
|
if (sector_sums[i].offset == offset) {
|
||||||
goto out;
|
printk("find ordered sum inode %lu offset %Lu\n", inode->i_ino, offset);
|
||||||
|
*sum = sector_sums[i].sum;
|
||||||
|
ret = 0;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
out:
|
out:
|
||||||
|
|
|
@ -39,7 +39,11 @@ struct btrfs_sector_sum {
|
||||||
|
|
||||||
struct btrfs_ordered_sum {
|
struct btrfs_ordered_sum {
|
||||||
u64 file_offset;
|
u64 file_offset;
|
||||||
u64 len;
|
/*
|
||||||
|
* this is the length in bytes covered by the sums array below.
|
||||||
|
* But, the sums array may not be contiguous in the file.
|
||||||
|
*/
|
||||||
|
unsigned long len;
|
||||||
struct list_head list;
|
struct list_head list;
|
||||||
/* last field is a variable length array of btrfs_sector_sums */
|
/* last field is a variable length array of btrfs_sector_sums */
|
||||||
struct btrfs_sector_sum sums;
|
struct btrfs_sector_sum sums;
|
||||||
|
@ -95,6 +99,7 @@ static inline int btrfs_ordered_sum_size(struct btrfs_root *root, u64 bytes)
|
||||||
{
|
{
|
||||||
unsigned long num_sectors = (bytes + root->sectorsize - 1) /
|
unsigned long num_sectors = (bytes + root->sectorsize - 1) /
|
||||||
root->sectorsize;
|
root->sectorsize;
|
||||||
|
num_sectors++;
|
||||||
return sizeof(struct btrfs_ordered_sum) +
|
return sizeof(struct btrfs_ordered_sum) +
|
||||||
num_sectors * sizeof(struct btrfs_sector_sum);
|
num_sectors * sizeof(struct btrfs_sector_sum);
|
||||||
}
|
}
|
||||||
|
@ -114,7 +119,9 @@ int btrfs_dec_test_ordered_pending(struct inode *inode,
|
||||||
u64 file_offset, u64 io_size);
|
u64 file_offset, u64 io_size);
|
||||||
int btrfs_add_ordered_extent(struct inode *inode, u64 file_offset,
|
int btrfs_add_ordered_extent(struct inode *inode, u64 file_offset,
|
||||||
u64 start, u64 len);
|
u64 start, u64 len);
|
||||||
int btrfs_add_ordered_sum(struct inode *inode, struct btrfs_ordered_sum *sum);
|
int btrfs_add_ordered_sum(struct inode *inode,
|
||||||
|
struct btrfs_ordered_extent *entry,
|
||||||
|
struct btrfs_ordered_sum *sum);
|
||||||
struct btrfs_ordered_extent *btrfs_lookup_ordered_extent(struct inode *inode,
|
struct btrfs_ordered_extent *btrfs_lookup_ordered_extent(struct inode *inode,
|
||||||
u64 file_offset);
|
u64 file_offset);
|
||||||
void btrfs_start_ordered_extent(struct inode *inode,
|
void btrfs_start_ordered_extent(struct inode *inode,
|
||||||
|
|
Loading…
Reference in a new issue