@@ -175,14 +175,16 @@ static int __btrfs_lookup_bio_sums(struct btrfs_root *root,
u32 diff;
int nblocks;
int bio_index = 0;
- int count;
+ int count, bvec_count;
u16 csum_size = btrfs_super_csum_size(root->fs_info->super_copy);
+ unsigned int blocks_per_bvec;
path = btrfs_alloc_path();
if (!path)
return -ENOMEM;
nblocks = bio->bi_size >> inode->i_sb->s_blocksize_bits;
+ blocks_per_bvec = bvec->bv_len >> inode->i_sb->s_blocksize_bits;
if (!dst) {
if (nblocks * csum_size > BTRFS_BIO_INLINE_CSUM_SIZE) {
btrfs_bio->csum_allocated = kmalloc(nblocks * csum_size,
@@ -221,8 +223,10 @@ static int __btrfs_lookup_bio_sums(struct btrfs_root *root,
if (dio)
offset = logical_offset;
while (bio_index < bio->bi_vcnt) {
+ bvec_count = 0;
if (!dio)
offset = page_offset(bvec->bv_page) + bvec->bv_offset;
+same_bvec:
count = btrfs_find_ordered_sum(inode, offset, disk_bytenr,
(u32 *)csum, nblocks);
if (count)
@@ -281,12 +285,26 @@ static int __btrfs_lookup_bio_sums(struct btrfs_root *root,
found:
csum += count * csum_size;
nblocks -= count;
- while (count--) {
+ while (count >= blocks_per_bvec) {
+ count -= blocks_per_bvec;
disk_bytenr += bvec->bv_len;
offset += bvec->bv_len;
bio_index++;
bvec++;
}
+
+ if (count) {
+ while (count--) {
+ bvec_count++;
+ disk_bytenr += inode->i_sb->s_blocksize;
+ offset += inode->i_sb->s_blocksize;
+ }
+ if (bvec_count == blocks_per_bvec) {
+ bio_index++;
+ bvec++;
+ } else
+ goto same_bvec;
+ }
}
btrfs_free_path(path);
return 0;
@@ -444,7 +462,8 @@ int btrfs_csum_one_bio(struct btrfs_root *root, struct inode *inode,
int index;
unsigned long total_bytes = 0;
unsigned long this_sum_bytes = 0;
- u64 offset;
+ u64 offset, pg_offset;
+ size_t csum_size;
WARN_ON(bio->bi_vcnt <= 0);
sums = kzalloc(btrfs_ordered_sum_size(root, bio->bi_size), GFP_NOFS);
@@ -489,17 +508,25 @@ int btrfs_csum_one_bio(struct btrfs_root *root, struct inode *inode,
index = 0;
}
+ if ((inode->i_sb->s_blocksize) < bvec->bv_len)
+ csum_size = inode->i_sb->s_blocksize;
+ else
+ csum_size = bvec->bv_len;
data = kmap_atomic(bvec->bv_page);
- sums->sums[index] = ~(u32)0;
- sums->sums[index] = btrfs_csum_data(data + bvec->bv_offset,
+ pg_offset = bvec->bv_offset;
+ while (pg_offset < bvec->bv_offset + bvec->bv_len) {
+ sums->sums[index] = ~(u32)0;
+ sums->sums[index] = btrfs_csum_data(data + pg_offset,
sums->sums[index],
- bvec->bv_len);
+ csum_size);
+ btrfs_csum_final(sums->sums[index],
+ (char *)(sums->sums + index));
+ index++;
+ pg_offset += csum_size;
+ }
kunmap_atomic(data);
- btrfs_csum_final(sums->sums[index],
- (char *)(sums->sums + index));
bio_index++;
- index++;
total_bytes += bvec->bv_len;
this_sum_bytes += bvec->bv_len;
offset += bvec->bv_len;
@@ -2781,6 +2781,7 @@ static int btrfs_readpage_end_io_hook(struct btrfs_io_bio *io_bio,
struct btrfs_root *root = BTRFS_I(inode)->root;
u32 csum_expected;
u32 csum = ~(u32)0;
+ u64 total_len, csum_len, csum_index;
static DEFINE_RATELIMIT_STATE(_rs, DEFAULT_RATELIMIT_INTERVAL,
DEFAULT_RATELIMIT_BURST);
@@ -2799,14 +2800,27 @@ static int btrfs_readpage_end_io_hook(struct btrfs_io_bio *io_bio,
return 0;
}
- phy_offset >>= inode->i_sb->s_blocksize_bits;
- csum_expected = *(((u32 *)io_bio->csum) + phy_offset);
+ total_len = end - start + 1;
+ if (inode->i_sb->s_blocksize < PAGE_CACHE_SIZE)
+ csum_len = inode->i_sb->s_blocksize;
+ else
+ csum_len = end - start + 1;
+
+ csum_index = phy_offset >> inode->i_sb->s_blocksize_bits;
kaddr = kmap_atomic(page);
- csum = btrfs_csum_data(kaddr + offset, csum, end - start + 1);
- btrfs_csum_final(csum, (char *)&csum);
- if (csum != csum_expected)
- goto zeroit;
+ while (total_len > 0) {
+ csum_expected = *(((u32 *)io_bio->csum) + csum_index);
+ csum = ~(u32)0;
+ csum = btrfs_csum_data(kaddr + offset, csum, csum_len);
+ btrfs_csum_final(csum, (char *)&csum);
+ if (csum != csum_expected)
+ goto zeroit;
+ offset += csum_len;
+ total_len -= csum_len;
+ csum_index += 1;
+ phy_offset += csum_len;
+ }
kunmap_atomic(kaddr);
good:
With subpagesize-blocksize, the IO is done in pages but checksums are calculated in blocks. This patch makes sure the checksums are calculated, stored, and verfied from proper indexes in the page. Signed-off-by: Chandra Seetharaman <sekharan@us.ibm.com> --- fs/btrfs/file-item.c | 45 ++++++++++++++++++++++++++++++++++++--------- fs/btrfs/inode.c | 26 ++++++++++++++++++++------ 2 files changed, 56 insertions(+), 15 deletions(-)