btrfs: don't assume compressed_bio sums to be 4 bytes
authorJohannes Thumshirn <jthumshirn@suse.de>
Wed, 22 May 2019 08:19:02 +0000 (10:19 +0200)
committerDavid Sterba <dsterba@suse.com>
Mon, 1 Jul 2019 11:35:01 +0000 (13:35 +0200)
BTRFS has the implicit assumption that a checksum in compressed_bio is 4
bytes. While this is true for CRC32C, it is not for any other checksum.

Change the data type to be a byte array and adjust loop index calculation
accordingly.

Signed-off-by: Johannes Thumshirn <jthumshirn@suse.de>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
fs/btrfs/compression.c
fs/btrfs/compression.h
fs/btrfs/file-item.c

index a8e551ca8798537c4e4edd822fe33c8ba9d9aff9..92291f2663245fa0f43f32c0b3834bbb2bc23427 100644 (file)
@@ -57,12 +57,14 @@ static int check_compressed_csum(struct btrfs_inode *inode,
                                 struct compressed_bio *cb,
                                 u64 disk_start)
 {
+       struct btrfs_fs_info *fs_info = inode->root->fs_info;
+       const u16 csum_size = btrfs_super_csum_size(fs_info->super_copy);
        int ret;
        struct page *page;
        unsigned long i;
        char *kaddr;
        u32 csum;
-       u32 *cb_sum = &cb->sums;
+       u8 *cb_sum = cb->sums;
 
        if (inode->flags & BTRFS_INODE_NODATASUM)
                return 0;
@@ -76,13 +78,13 @@ static int check_compressed_csum(struct btrfs_inode *inode,
                btrfs_csum_final(csum, (u8 *)&csum);
                kunmap_atomic(kaddr);
 
-               if (csum != *cb_sum) {
+               if (memcmp(&csum, cb_sum, csum_size)) {
                        btrfs_print_data_csum_error(inode, disk_start, csum,
-                                       *cb_sum, cb->mirror_num);
+                                       *(u32 *)cb_sum, cb->mirror_num);
                        ret = -EIO;
                        goto fail;
                }
-               cb_sum++;
+               cb_sum += csum_size;
 
        }
        ret = 0;
@@ -536,7 +538,8 @@ blk_status_t btrfs_submit_compressed_read(struct inode *inode, struct bio *bio,
        struct extent_map *em;
        blk_status_t ret = BLK_STS_RESOURCE;
        int faili = 0;
-       u32 *sums;
+       const u16 csum_size = btrfs_super_csum_size(fs_info->super_copy);
+       u8 *sums;
 
        em_tree = &BTRFS_I(inode)->extent_tree;
 
@@ -558,7 +561,7 @@ blk_status_t btrfs_submit_compressed_read(struct inode *inode, struct bio *bio,
        cb->errors = 0;
        cb->inode = inode;
        cb->mirror_num = mirror_num;
-       sums = &cb->sums;
+       sums = cb->sums;
 
        cb->start = em->orig_start;
        em_len = em->len;
@@ -617,6 +620,8 @@ blk_status_t btrfs_submit_compressed_read(struct inode *inode, struct bio *bio,
                page->mapping = NULL;
                if (submit || bio_add_page(comp_bio, page, PAGE_SIZE, 0) <
                    PAGE_SIZE) {
+                       unsigned int nr_sectors;
+
                        ret = btrfs_bio_wq_end_io(fs_info, comp_bio,
                                                  BTRFS_WQ_ENDIO_DATA);
                        BUG_ON(ret); /* -ENOMEM */
@@ -631,11 +636,13 @@ blk_status_t btrfs_submit_compressed_read(struct inode *inode, struct bio *bio,
 
                        if (!(BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM)) {
                                ret = btrfs_lookup_bio_sums(inode, comp_bio,
-                                                           (u8 *)sums);
+                                                           sums);
                                BUG_ON(ret); /* -ENOMEM */
                        }
-                       sums += DIV_ROUND_UP(comp_bio->bi_iter.bi_size,
-                                            fs_info->sectorsize);
+
+                       nr_sectors = DIV_ROUND_UP(comp_bio->bi_iter.bi_size,
+                                                 fs_info->sectorsize);
+                       sums += csum_size * nr_sectors;
 
                        ret = btrfs_map_bio(fs_info, comp_bio, mirror_num, 0);
                        if (ret) {
@@ -657,7 +664,7 @@ blk_status_t btrfs_submit_compressed_read(struct inode *inode, struct bio *bio,
        BUG_ON(ret); /* -ENOMEM */
 
        if (!(BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM)) {
-               ret = btrfs_lookup_bio_sums(inode, comp_bio, (u8 *) sums);
+               ret = btrfs_lookup_bio_sums(inode, comp_bio, sums);
                BUG_ON(ret); /* -ENOMEM */
        }
 
index 9976fe0f752670923df0e4fd01fa8a2f96e6ad6d..191e5f4e3523be28f344970dc756f3e7aba258bd 100644 (file)
@@ -61,7 +61,7 @@ struct compressed_bio {
         * the start of a variable length array of checksums only
         * used by reads
         */
-       u32 sums;
+       u8 sums[];
 };
 
 static inline unsigned int btrfs_compress_type(unsigned int type_level)
index 0464dd4c05797440314584e09b7a5e905bcf67b5..de89fd1310a6bef5be35e74dde86ab14f2d59dc3 100644 (file)
@@ -186,7 +186,7 @@ static blk_status_t __btrfs_lookup_bio_sums(struct inode *inode, struct bio *bio
                }
                csum = btrfs_bio->csum;
        } else {
-               csum = (u8 *)dst;
+               csum = dst;
        }
 
        if (bio->bi_iter.bi_size > PAGE_SIZE * 8)