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: 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>
This commit is contained in:
Родитель
4bb3c2e2b5
Коммит
1e25a2e3ca
|
@ -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)) {
|
if (!(BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM)) {
|
||||||
ret = btrfs_lookup_bio_sums(inode, comp_bio,
|
ret = btrfs_lookup_bio_sums(inode, comp_bio,
|
||||||
sums);
|
(u8 *)sums);
|
||||||
BUG_ON(ret); /* -ENOMEM */
|
BUG_ON(ret); /* -ENOMEM */
|
||||||
}
|
}
|
||||||
sums += DIV_ROUND_UP(comp_bio->bi_iter.bi_size,
|
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 */
|
BUG_ON(ret); /* -ENOMEM */
|
||||||
|
|
||||||
if (!(BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM)) {
|
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 */
|
BUG_ON(ret); /* -ENOMEM */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3199,7 +3199,8 @@ int btrfs_find_name_in_ext_backref(struct extent_buffer *leaf, int slot,
|
||||||
struct btrfs_dio_private;
|
struct btrfs_dio_private;
|
||||||
int btrfs_del_csums(struct btrfs_trans_handle *trans,
|
int btrfs_del_csums(struct btrfs_trans_handle *trans,
|
||||||
struct btrfs_fs_info *fs_info, u64 bytenr, u64 len);
|
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,
|
blk_status_t btrfs_lookup_bio_sums_dio(struct inode *inode, struct bio *bio,
|
||||||
u64 logical_offset);
|
u64 logical_offset);
|
||||||
int btrfs_insert_file_extent(struct btrfs_trans_handle *trans,
|
int btrfs_insert_file_extent(struct btrfs_trans_handle *trans,
|
||||||
|
|
|
@ -22,9 +22,13 @@
|
||||||
#define MAX_CSUM_ITEMS(r, size) (min_t(u32, __MAX_CSUM_ITEMS(r, size), \
|
#define MAX_CSUM_ITEMS(r, size) (min_t(u32, __MAX_CSUM_ITEMS(r, size), \
|
||||||
PAGE_SIZE))
|
PAGE_SIZE))
|
||||||
|
|
||||||
#define MAX_ORDERED_SUM_BYTES(fs_info) ((PAGE_SIZE - \
|
static inline u32 max_ordered_sum_bytes(struct btrfs_fs_info *fs_info,
|
||||||
sizeof(struct btrfs_ordered_sum)) / \
|
u16 csum_size)
|
||||||
sizeof(u32) * (fs_info)->sectorsize)
|
{
|
||||||
|
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,
|
int btrfs_insert_file_extent(struct btrfs_trans_handle *trans,
|
||||||
struct btrfs_root *root,
|
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,
|
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 btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
|
||||||
struct bio_vec bvec;
|
struct bio_vec bvec;
|
||||||
|
@ -211,7 +215,7 @@ static blk_status_t __btrfs_lookup_bio_sums(struct inode *inode, struct bio *bio
|
||||||
if (!dio)
|
if (!dio)
|
||||||
offset = page_offset(bvec.bv_page) + bvec.bv_offset;
|
offset = page_offset(bvec.bv_page) + bvec.bv_offset;
|
||||||
count = btrfs_find_ordered_sum(inode, offset, disk_bytenr,
|
count = btrfs_find_ordered_sum(inode, offset, disk_bytenr,
|
||||||
(u32 *)csum, nblocks);
|
csum, nblocks);
|
||||||
if (count)
|
if (count)
|
||||||
goto found;
|
goto found;
|
||||||
|
|
||||||
|
@ -283,7 +287,8 @@ next:
|
||||||
return 0;
|
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);
|
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);
|
struct btrfs_csum_item);
|
||||||
while (start < csum_end) {
|
while (start < csum_end) {
|
||||||
size = min_t(size_t, csum_end - start,
|
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),
|
sums = kzalloc(btrfs_ordered_sum_size(fs_info, size),
|
||||||
GFP_NOFS);
|
GFP_NOFS);
|
||||||
if (!sums) {
|
if (!sums) {
|
||||||
|
@ -439,6 +444,7 @@ blk_status_t btrfs_csum_one_bio(struct inode *inode, struct bio *bio,
|
||||||
int i;
|
int i;
|
||||||
u64 offset;
|
u64 offset;
|
||||||
unsigned nofs_flag;
|
unsigned nofs_flag;
|
||||||
|
const u16 csum_size = btrfs_super_csum_size(fs_info->super_copy);
|
||||||
|
|
||||||
nofs_flag = memalloc_nofs_save();
|
nofs_flag = memalloc_nofs_save();
|
||||||
sums = kvzalloc(btrfs_ordered_sum_size(fs_info, bio->bi_iter.bi_size),
|
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);
|
- 1);
|
||||||
|
|
||||||
for (i = 0; i < nr_sectors; i++) {
|
for (i = 0; i < nr_sectors; i++) {
|
||||||
|
u32 tmp;
|
||||||
|
|
||||||
if (offset >= ordered->file_offset + ordered->len ||
|
if (offset >= ordered->file_offset + ordered->len ||
|
||||||
offset < ordered->file_offset) {
|
offset < ordered->file_offset) {
|
||||||
unsigned long bytes_left;
|
unsigned long bytes_left;
|
||||||
|
@ -498,17 +506,16 @@ blk_status_t btrfs_csum_one_bio(struct inode *inode, struct bio *bio,
|
||||||
index = 0;
|
index = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
sums->sums[index] = ~(u32)0;
|
memset(&sums->sums[index], 0xff, csum_size);
|
||||||
data = kmap_atomic(bvec.bv_page);
|
data = kmap_atomic(bvec.bv_page);
|
||||||
sums->sums[index]
|
tmp = btrfs_csum_data(data + bvec.bv_offset
|
||||||
= btrfs_csum_data(data + bvec.bv_offset
|
|
||||||
+ (i * fs_info->sectorsize),
|
+ (i * fs_info->sectorsize),
|
||||||
sums->sums[index],
|
*(u32 *)&sums->sums[index],
|
||||||
fs_info->sectorsize);
|
fs_info->sectorsize);
|
||||||
kunmap_atomic(data);
|
kunmap_atomic(data);
|
||||||
btrfs_csum_final(sums->sums[index],
|
btrfs_csum_final(tmp,
|
||||||
(char *)(sums->sums + index));
|
(char *)(sums->sums + index));
|
||||||
index++;
|
index += csum_size;
|
||||||
offset += fs_info->sectorsize;
|
offset += fs_info->sectorsize;
|
||||||
this_sum_bytes += fs_info->sectorsize;
|
this_sum_bytes += fs_info->sectorsize;
|
||||||
total_bytes += fs_info->sectorsize;
|
total_bytes += fs_info->sectorsize;
|
||||||
|
@ -904,9 +911,9 @@ found:
|
||||||
write_extent_buffer(leaf, sums->sums + index, (unsigned long)item,
|
write_extent_buffer(leaf, sums->sums + index, (unsigned long)item,
|
||||||
ins_size);
|
ins_size);
|
||||||
|
|
||||||
|
index += ins_size;
|
||||||
ins_size /= csum_size;
|
ins_size /= csum_size;
|
||||||
total_bytes += ins_size * fs_info->sectorsize;
|
total_bytes += ins_size * fs_info->sectorsize;
|
||||||
index += ins_size;
|
|
||||||
|
|
||||||
btrfs_mark_buffer_dirty(path->nodes[0]);
|
btrfs_mark_buffer_dirty(path->nodes[0]);
|
||||||
if (total_bytes < sums->len) {
|
if (total_bytes < sums->len) {
|
||||||
|
|
|
@ -924,14 +924,16 @@ out:
|
||||||
* be reclaimed before their checksum is actually put into the btree
|
* be reclaimed before their checksum is actually put into the btree
|
||||||
*/
|
*/
|
||||||
int btrfs_find_ordered_sum(struct inode *inode, u64 offset, u64 disk_bytenr,
|
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_sum *ordered_sum;
|
||||||
struct btrfs_ordered_extent *ordered;
|
struct btrfs_ordered_extent *ordered;
|
||||||
struct btrfs_ordered_inode_tree *tree = &BTRFS_I(inode)->ordered_tree;
|
struct btrfs_ordered_inode_tree *tree = &BTRFS_I(inode)->ordered_tree;
|
||||||
unsigned long num_sectors;
|
unsigned long num_sectors;
|
||||||
unsigned long i;
|
unsigned long i;
|
||||||
u32 sectorsize = btrfs_inode_sectorsize(inode);
|
u32 sectorsize = btrfs_inode_sectorsize(inode);
|
||||||
|
const u16 csum_size = btrfs_super_csum_size(fs_info->super_copy);
|
||||||
int index = 0;
|
int index = 0;
|
||||||
|
|
||||||
ordered = btrfs_lookup_ordered_extent(inode, offset);
|
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 >>
|
num_sectors = ordered_sum->len >>
|
||||||
inode->i_sb->s_blocksize_bits;
|
inode->i_sb->s_blocksize_bits;
|
||||||
num_sectors = min_t(int, len - index, num_sectors - i);
|
num_sectors = min_t(int, len - index, num_sectors - i);
|
||||||
memcpy(sum + index, ordered_sum->sums + i,
|
memcpy(sum + index, ordered_sum->sums + i * csum_size,
|
||||||
num_sectors);
|
num_sectors * csum_size);
|
||||||
|
|
||||||
index += (int)num_sectors;
|
index += (int)num_sectors * csum_size;
|
||||||
if (index == len)
|
if (index == len)
|
||||||
goto out;
|
goto out;
|
||||||
disk_bytenr += num_sectors * sectorsize;
|
disk_bytenr += num_sectors * sectorsize;
|
||||||
|
|
|
@ -23,7 +23,7 @@ struct btrfs_ordered_sum {
|
||||||
int len;
|
int len;
|
||||||
struct list_head list;
|
struct list_head list;
|
||||||
/* last field is a variable length array of csums */
|
/* 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,
|
int btrfs_ordered_update_i_size(struct inode *inode, u64 offset,
|
||||||
struct btrfs_ordered_extent *ordered);
|
struct btrfs_ordered_extent *ordered);
|
||||||
int btrfs_find_ordered_sum(struct inode *inode, u64 offset, u64 disk_bytenr,
|
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,
|
u64 btrfs_wait_ordered_extents(struct btrfs_root *root, u64 nr,
|
||||||
const u64 range_start, const u64 range_len);
|
const u64 range_start, const u64 range_len);
|
||||||
u64 btrfs_wait_ordered_roots(struct btrfs_fs_info *fs_info, u64 nr,
|
u64 btrfs_wait_ordered_roots(struct btrfs_fs_info *fs_info, u64 nr,
|
||||||
|
|
|
@ -2448,7 +2448,7 @@ static int scrub_find_csum(struct scrub_ctx *sctx, u64 logical, u8 *csum)
|
||||||
ASSERT(index < UINT_MAX);
|
ASSERT(index < UINT_MAX);
|
||||||
|
|
||||||
num_sectors = sum->len / sctx->fs_info->sectorsize;
|
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) {
|
if (index == num_sectors - 1) {
|
||||||
list_del(&sum->list);
|
list_del(&sum->list);
|
||||||
kfree(sum);
|
kfree(sum);
|
||||||
|
|
Загрузка…
Ссылка в новой задаче