btrfs: don't assume ordered sums to be 4 bytes
authorJohannes Thumshirn <jthumshirn@suse.de>
Wed, 22 May 2019 08:19:01 +0000 (10:19 +0200)
committerDavid Sterba <dsterba@suse.com>
Mon, 1 Jul 2019 11:35:00 +0000 (13:35 +0200)
BTRFS has the implicit assumption that a checksum in btrfs_orderd_sums
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.

This includes moving the adjustment of 'index' by 'ins_size' in
btrfs_csum_file_blocks() before dividing 'ins_size' by the checksum
size, because before this patch the 'sums' member of 'struct
btrfs_ordered_sum' was 4 Bytes in size and afterwards it is only one
byte.

Reviewed-by: Nikolay Borisov <nborisov@suse.com>
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/ctree.h
fs/btrfs/file-item.c
fs/btrfs/ordered-data.c
fs/btrfs/ordered-data.h
fs/btrfs/scrub.c

index 84dd4a8980c5c83dbd8281757dfb788c62495702..a8e551ca8798537c4e4edd822fe33c8ba9d9aff9 100644 (file)
@@ -631,7 +631,7 @@ 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,
-                                                           sums);
+                                                           (u8 *)sums);
                                BUG_ON(ret); /* -ENOMEM */
                        }
                        sums += DIV_ROUND_UP(comp_bio->bi_iter.bi_size,
@@ -657,7 +657,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, sums);
+               ret = btrfs_lookup_bio_sums(inode, comp_bio, (u8 *) sums);
                BUG_ON(ret); /* -ENOMEM */
        }
 
index 3691cd177ead09c34a0ea02d6d67e02bdd668004..a66ed58058d94731c6c6be1f24d73d1688b484be 100644 (file)
@@ -3199,7 +3199,8 @@ int btrfs_find_name_in_ext_backref(struct extent_buffer *leaf, int slot,
 struct btrfs_dio_private;
 int btrfs_del_csums(struct btrfs_trans_handle *trans,
                    struct btrfs_fs_info *fs_info, u64 bytenr, u64 len);
-blk_status_t btrfs_lookup_bio_sums(struct inode *inode, struct bio *bio, u32 *dst);
+blk_status_t btrfs_lookup_bio_sums(struct inode *inode, struct bio *bio,
+                                  u8 *dst);
 blk_status_t btrfs_lookup_bio_sums_dio(struct inode *inode, struct bio *bio,
                              u64 logical_offset);
 int btrfs_insert_file_extent(struct btrfs_trans_handle *trans,
index d431ea8198e411e1ce88937179fc0f5e1e519770..0464dd4c05797440314584e09b7a5e905bcf67b5 100644 (file)
 #define MAX_CSUM_ITEMS(r, size) (min_t(u32, __MAX_CSUM_ITEMS(r, size), \
                                       PAGE_SIZE))
 
-#define MAX_ORDERED_SUM_BYTES(fs_info) ((PAGE_SIZE - \
-                                  sizeof(struct btrfs_ordered_sum)) / \
-                                  sizeof(u32) * (fs_info)->sectorsize)
+static inline u32 max_ordered_sum_bytes(struct btrfs_fs_info *fs_info,
+                                       u16 csum_size)
+{
+       u32 ncsums = (PAGE_SIZE - sizeof(struct btrfs_ordered_sum)) / csum_size;
+
+       return ncsums * fs_info->sectorsize;
+}
 
 int btrfs_insert_file_extent(struct btrfs_trans_handle *trans,
                             struct btrfs_root *root,
@@ -144,7 +148,7 @@ int btrfs_lookup_file_extent(struct btrfs_trans_handle *trans,
 }
 
 static blk_status_t __btrfs_lookup_bio_sums(struct inode *inode, struct bio *bio,
-                                  u64 logical_offset, u32 *dst, int dio)
+                                  u64 logical_offset, u8 *dst, int dio)
 {
        struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
        struct bio_vec bvec;
@@ -211,7 +215,7 @@ static blk_status_t __btrfs_lookup_bio_sums(struct inode *inode, struct bio *bio
                if (!dio)
                        offset = page_offset(bvec.bv_page) + bvec.bv_offset;
                count = btrfs_find_ordered_sum(inode, offset, disk_bytenr,
-                                              (u32 *)csum, nblocks);
+                                              csum, nblocks);
                if (count)
                        goto found;
 
@@ -283,7 +287,8 @@ next:
        return 0;
 }
 
-blk_status_t btrfs_lookup_bio_sums(struct inode *inode, struct bio *bio, u32 *dst)
+blk_status_t btrfs_lookup_bio_sums(struct inode *inode, struct bio *bio,
+                                  u8 *dst)
 {
        return __btrfs_lookup_bio_sums(inode, bio, 0, dst, 0);
 }
@@ -374,7 +379,7 @@ int btrfs_lookup_csums_range(struct btrfs_root *root, u64 start, u64 end,
                                      struct btrfs_csum_item);
                while (start < csum_end) {
                        size = min_t(size_t, csum_end - start,
-                                    MAX_ORDERED_SUM_BYTES(fs_info));
+                                    max_ordered_sum_bytes(fs_info, csum_size));
                        sums = kzalloc(btrfs_ordered_sum_size(fs_info, size),
                                       GFP_NOFS);
                        if (!sums) {
@@ -439,6 +444,7 @@ blk_status_t btrfs_csum_one_bio(struct inode *inode, struct bio *bio,
        int i;
        u64 offset;
        unsigned nofs_flag;
+       const u16 csum_size = btrfs_super_csum_size(fs_info->super_copy);
 
        nofs_flag = memalloc_nofs_save();
        sums = kvzalloc(btrfs_ordered_sum_size(fs_info, bio->bi_iter.bi_size),
@@ -473,6 +479,8 @@ blk_status_t btrfs_csum_one_bio(struct inode *inode, struct bio *bio,
                                                 - 1);
 
                for (i = 0; i < nr_sectors; i++) {
+                       u32 tmp;
+
                        if (offset >= ordered->file_offset + ordered->len ||
                                offset < ordered->file_offset) {
                                unsigned long bytes_left;
@@ -498,17 +506,16 @@ blk_status_t btrfs_csum_one_bio(struct inode *inode, struct bio *bio,
                                index = 0;
                        }
 
-                       sums->sums[index] = ~(u32)0;
+                       memset(&sums->sums[index], 0xff, csum_size);
                        data = kmap_atomic(bvec.bv_page);
-                       sums->sums[index]
-                               = btrfs_csum_data(data + bvec.bv_offset
+                       tmp = btrfs_csum_data(data + bvec.bv_offset
                                                + (i * fs_info->sectorsize),
-                                               sums->sums[index],
+                                               *(u32 *)&sums->sums[index],
                                                fs_info->sectorsize);
                        kunmap_atomic(data);
-                       btrfs_csum_final(sums->sums[index],
+                       btrfs_csum_final(tmp,
                                        (char *)(sums->sums + index));
-                       index++;
+                       index += csum_size;
                        offset += fs_info->sectorsize;
                        this_sum_bytes += fs_info->sectorsize;
                        total_bytes += fs_info->sectorsize;
@@ -904,9 +911,9 @@ found:
        write_extent_buffer(leaf, sums->sums + index, (unsigned long)item,
                            ins_size);
 
+       index += ins_size;
        ins_size /= csum_size;
        total_bytes += ins_size * fs_info->sectorsize;
-       index += ins_size;
 
        btrfs_mark_buffer_dirty(path->nodes[0]);
        if (total_bytes < sums->len) {
index df02ed25b7dba165b71dfc73542de0eb4b0798ea..3f67b7827393ceaac9fd8d54699e33318446c678 100644 (file)
@@ -924,14 +924,16 @@ out:
  * be reclaimed before their checksum is actually put into the btree
  */
 int btrfs_find_ordered_sum(struct inode *inode, u64 offset, u64 disk_bytenr,
-                          u32 *sum, int len)
+                          u8 *sum, int len)
 {
+       struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
        struct btrfs_ordered_sum *ordered_sum;
        struct btrfs_ordered_extent *ordered;
        struct btrfs_ordered_inode_tree *tree = &BTRFS_I(inode)->ordered_tree;
        unsigned long num_sectors;
        unsigned long i;
        u32 sectorsize = btrfs_inode_sectorsize(inode);
+       const u16 csum_size = btrfs_super_csum_size(fs_info->super_copy);
        int index = 0;
 
        ordered = btrfs_lookup_ordered_extent(inode, offset);
@@ -947,10 +949,10 @@ int btrfs_find_ordered_sum(struct inode *inode, u64 offset, u64 disk_bytenr,
                        num_sectors = ordered_sum->len >>
                                      inode->i_sb->s_blocksize_bits;
                        num_sectors = min_t(int, len - index, num_sectors - i);
-                       memcpy(sum + index, ordered_sum->sums + i,
-                              num_sectors);
+                       memcpy(sum + index, ordered_sum->sums + i * csum_size,
+                              num_sectors * csum_size);
 
-                       index += (int)num_sectors;
+                       index += (int)num_sectors * csum_size;
                        if (index == len)
                                goto out;
                        disk_bytenr += num_sectors * sectorsize;
index 9b68179d580f8d6c8ea948eb109a612342868e2a..5204171ea9622f8d73ff4ac649e5d8a828ead439 100644 (file)
@@ -23,7 +23,7 @@ struct btrfs_ordered_sum {
        int len;
        struct list_head list;
        /* last field is a variable length array of csums */
-       u32 sums[];
+       u8 sums[];
 };
 
 /*
@@ -183,7 +183,7 @@ struct btrfs_ordered_extent *btrfs_lookup_ordered_range(
 int btrfs_ordered_update_i_size(struct inode *inode, u64 offset,
                                struct btrfs_ordered_extent *ordered);
 int btrfs_find_ordered_sum(struct inode *inode, u64 offset, u64 disk_bytenr,
-                          u32 *sum, int len);
+                          u8 *sum, int len);
 u64 btrfs_wait_ordered_extents(struct btrfs_root *root, u64 nr,
                               const u64 range_start, const u64 range_len);
 u64 btrfs_wait_ordered_roots(struct btrfs_fs_info *fs_info, u64 nr,
index e51929a55af4c3902116deb9f1af7bb3ec11a4ec..0e77bffd2a5a8c719af7ab84bde47b8a747ea1b6 100644 (file)
@@ -2448,7 +2448,7 @@ static int scrub_find_csum(struct scrub_ctx *sctx, u64 logical, u8 *csum)
        ASSERT(index < UINT_MAX);
 
        num_sectors = sum->len / sctx->fs_info->sectorsize;
-       memcpy(csum, sum->sums + index, sctx->csum_size);
+       memcpy(csum, sum->sums + index * sctx->csum_size, sctx->csum_size);
        if (index == num_sectors - 1) {
                list_del(&sum->list);
                kfree(sum);