Skip to content

Commit

Permalink
Btrfs: Handle data checksumming on bios that span multiple ordered ex…
Browse files Browse the repository at this point in the history
…tents

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>
  • Loading branch information
chrismason-xx committed Sep 25, 2008
1 parent eb84ae0 commit 3edf7d3
Show file tree
Hide file tree
Showing 5 changed files with 69 additions and 31 deletions.
4 changes: 2 additions & 2 deletions fs/btrfs/ctree.h
Original file line number Diff line number Diff line change
Expand Up @@ -1579,8 +1579,8 @@ int btrfs_lookup_file_extent(struct btrfs_trans_handle *trans,
int btrfs_csum_file_blocks(struct btrfs_trans_handle *trans,
struct btrfs_root *root, struct inode *inode,
struct btrfs_ordered_sum *sums);
int btrfs_csum_one_bio(struct btrfs_root *root,
struct bio *bio, struct btrfs_ordered_sum **sums_ret);
int btrfs_csum_one_bio(struct btrfs_root *root, struct inode *inode,
struct bio *bio);
struct btrfs_csum_item *btrfs_lookup_csum(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
struct btrfs_path *path,
Expand Down
43 changes: 39 additions & 4 deletions fs/btrfs/file-item.c
Original file line number Diff line number Diff line change
Expand Up @@ -134,26 +134,53 @@ int btrfs_lookup_file_extent(struct btrfs_trans_handle *trans,
return ret;
}

int btrfs_csum_one_bio(struct btrfs_root *root,
struct bio *bio, struct btrfs_ordered_sum **sums_ret)
int btrfs_csum_one_bio(struct btrfs_root *root, struct inode *inode,
struct bio *bio)
{
struct btrfs_ordered_sum *sums;
struct btrfs_sector_sum *sector_sum;
struct btrfs_ordered_extent *ordered;
char *data;
struct bio_vec *bvec = bio->bi_io_vec;
int bio_index = 0;
unsigned long total_bytes = 0;
unsigned long this_sum_bytes = 0;
u64 offset;

WARN_ON(bio->bi_vcnt <= 0);
sums = kzalloc(btrfs_ordered_sum_size(root, bio->bi_size), GFP_NOFS);
if (!sums)
return -ENOMEM;
*sums_ret = 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;
INIT_LIST_HEAD(&sums->list);
ordered = btrfs_lookup_ordered_extent(inode, sums->file_offset);
BUG_ON(!ordered);

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);
sector_sum->sum = ~(u32)0;
sector_sum->sum = btrfs_csum_data(root,
Expand All @@ -165,10 +192,18 @@ int btrfs_csum_one_bio(struct btrfs_root *root,
(char *)&sector_sum->sum);
sector_sum->offset = page_offset(bvec->bv_page) +
bvec->bv_offset;

sector_sum++;
bio_index++;
total_bytes += bvec->bv_len;
this_sum_bytes += bvec->bv_len;
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;
}

Expand Down
6 changes: 1 addition & 5 deletions fs/btrfs/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
int ret = 0;
struct btrfs_ordered_sum *sums;

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

ret = btrfs_add_ordered_sum(inode, sums);
ret = btrfs_csum_one_bio(root, inode, bio);
BUG_ON(ret);

return btrfs_map_bio(root, rw, bio, mirror_num, 1);
Expand Down
36 changes: 18 additions & 18 deletions fs/btrfs/ordered-data.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
* 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 rb_node *node;
struct btrfs_ordered_extent *entry;

tree = &BTRFS_I(inode)->ordered_tree;
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);
mutex_unlock(&tree->mutex);
return 0;
Expand Down Expand Up @@ -524,8 +519,10 @@ int btrfs_find_ordered_sum(struct inode *inode, u64 offset, u32 *sum)
struct btrfs_ordered_extent *ordered;
struct btrfs_ordered_inode_tree *tree = &BTRFS_I(inode)->ordered_tree;
struct list_head *cur;
unsigned long num_sectors;
unsigned long i;
u32 sectorsize = BTRFS_I(inode)->root->sectorsize;
int ret = 1;
int index;

ordered = btrfs_lookup_ordered_extent(inode, offset);
if (!ordered)
Expand All @@ -534,14 +531,17 @@ int btrfs_find_ordered_sum(struct inode *inode, u64 offset, u32 *sum)
mutex_lock(&tree->mutex);
list_for_each_prev(cur, &ordered->list) {
ordered_sum = list_entry(cur, struct btrfs_ordered_sum, list);
if (offset >= ordered_sum->file_offset &&
offset < ordered_sum->file_offset + ordered_sum->len) {
index = (offset - ordered_sum->file_offset) /
BTRFS_I(inode)->root->sectorsize;;
if (offset >= ordered_sum->file_offset) {
num_sectors = ordered_sum->len / sectorsize;
sector_sums = &ordered_sum->sums;
*sum = sector_sums[index].sum;
ret = 0;
goto out;
for (i = 0; i < num_sectors; i++) {
if (sector_sums[i].offset == offset) {
printk("find ordered sum inode %lu offset %Lu\n", inode->i_ino, offset);
*sum = sector_sums[i].sum;
ret = 0;
goto out;
}
}
}
}
out:
Expand Down
11 changes: 9 additions & 2 deletions fs/btrfs/ordered-data.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,11 @@ struct btrfs_sector_sum {

struct btrfs_ordered_sum {
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;
/* last field is a variable length array of btrfs_sector_sums */
struct btrfs_sector_sum sums;
Expand Down Expand Up @@ -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) /
root->sectorsize;
num_sectors++;
return sizeof(struct btrfs_ordered_sum) +
num_sectors * sizeof(struct btrfs_sector_sum);
}
Expand All @@ -114,7 +119,9 @@ int btrfs_dec_test_ordered_pending(struct inode *inode,
u64 file_offset, u64 io_size);
int btrfs_add_ordered_extent(struct inode *inode, u64 file_offset,
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,
u64 file_offset);
void btrfs_start_ordered_extent(struct inode *inode,
Expand Down

0 comments on commit 3edf7d3

Please sign in to comment.