Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1e25a2e3 authored by Johannes Thumshirn's avatar Johannes Thumshirn Committed by David Sterba
Browse files

btrfs: don't assume ordered sums to be 4 bytes



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: default avatarNikolay Borisov <nborisov@suse.com>
Signed-off-by: default avatarJohannes Thumshirn <jthumshirn@suse.de>
Reviewed-by: default avatarDavid Sterba <dsterba@suse.com>
Signed-off-by: default avatarDavid Sterba <dsterba@suse.com>
parent 4bb3c2e2
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -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 */
	}

+2 −1
Original line number Diff line number Diff line
@@ -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,
+21 −14
Original line number Diff line number Diff line
@@ -22,9 +22,13 @@
#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 @@ static blk_status_t __btrfs_lookup_bio_sums(struct inode *inode, struct bio *bio
	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 @@ int btrfs_csum_file_blocks(struct btrfs_trans_handle *trans,
	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) {
+6 −4
Original line number Diff line number Diff line
@@ -924,14 +924,16 @@ int btrfs_ordered_update_i_size(struct inode *inode, u64 offset,
 * 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;
+2 −2
Original line number Diff line number Diff line
@@ -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,
Loading