mirror of
https://gitee.com/bianbu-linux/linux-6.6
synced 2025-04-24 14:07:52 -04:00
btrfs: introduce a data checksum checking helper
Although we have several data csum verification code, we never have a function really just to verify checksum for one sector. Function check_data_csum() do extra work for error reporting, thus it requires a lot of extra things like file offset, bio_offset etc. Function btrfs_verify_data_csum() is even worse, it will utilize page checked flag, which means it can not be utilized for direct IO pages. Here we introduce a new helper, btrfs_check_sector_csum(), which really only accept a sector in page, and expected checksum pointer. We use this function to implement check_data_csum(), and export it for incoming patch. Reviewed-by: Nikolay Borisov <nborisov@suse.com> Signed-off-by: Qu Wenruo <wqu@suse.com> [hch: keep passing the csum array as an arguments, as the callers want to print it, rename per request] Signed-off-by: Christoph Hellwig <hch@lst.de> Reviewed-by: David Sterba <dsterba@suse.com> Signed-off-by: David Sterba <dsterba@suse.com>
This commit is contained in:
parent
b036f47996
commit
ae643a74eb
3 changed files with 34 additions and 19 deletions
|
@ -147,12 +147,10 @@ static int check_compressed_csum(struct btrfs_inode *inode, struct bio *bio,
|
||||||
u64 disk_start)
|
u64 disk_start)
|
||||||
{
|
{
|
||||||
struct btrfs_fs_info *fs_info = inode->root->fs_info;
|
struct btrfs_fs_info *fs_info = inode->root->fs_info;
|
||||||
SHASH_DESC_ON_STACK(shash, fs_info->csum_shash);
|
|
||||||
const u32 csum_size = fs_info->csum_size;
|
const u32 csum_size = fs_info->csum_size;
|
||||||
const u32 sectorsize = fs_info->sectorsize;
|
const u32 sectorsize = fs_info->sectorsize;
|
||||||
struct page *page;
|
struct page *page;
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
char *kaddr;
|
|
||||||
u8 csum[BTRFS_CSUM_SIZE];
|
u8 csum[BTRFS_CSUM_SIZE];
|
||||||
struct compressed_bio *cb = bio->bi_private;
|
struct compressed_bio *cb = bio->bi_private;
|
||||||
u8 *cb_sum = cb->sums;
|
u8 *cb_sum = cb->sums;
|
||||||
|
@ -161,8 +159,6 @@ static int check_compressed_csum(struct btrfs_inode *inode, struct bio *bio,
|
||||||
test_bit(BTRFS_FS_STATE_NO_CSUMS, &fs_info->fs_state))
|
test_bit(BTRFS_FS_STATE_NO_CSUMS, &fs_info->fs_state))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
shash->tfm = fs_info->csum_shash;
|
|
||||||
|
|
||||||
for (i = 0; i < cb->nr_pages; i++) {
|
for (i = 0; i < cb->nr_pages; i++) {
|
||||||
u32 pg_offset;
|
u32 pg_offset;
|
||||||
u32 bytes_left = PAGE_SIZE;
|
u32 bytes_left = PAGE_SIZE;
|
||||||
|
@ -175,12 +171,11 @@ static int check_compressed_csum(struct btrfs_inode *inode, struct bio *bio,
|
||||||
/* Hash through the page sector by sector */
|
/* Hash through the page sector by sector */
|
||||||
for (pg_offset = 0; pg_offset < bytes_left;
|
for (pg_offset = 0; pg_offset < bytes_left;
|
||||||
pg_offset += sectorsize) {
|
pg_offset += sectorsize) {
|
||||||
kaddr = kmap_atomic(page);
|
int ret;
|
||||||
crypto_shash_digest(shash, kaddr + pg_offset,
|
|
||||||
sectorsize, csum);
|
|
||||||
kunmap_atomic(kaddr);
|
|
||||||
|
|
||||||
if (memcmp(&csum, cb_sum, csum_size) != 0) {
|
ret = btrfs_check_sector_csum(fs_info, page, pg_offset,
|
||||||
|
csum, cb_sum);
|
||||||
|
if (ret) {
|
||||||
btrfs_print_data_csum_error(inode, disk_start,
|
btrfs_print_data_csum_error(inode, disk_start,
|
||||||
csum, cb_sum, cb->mirror_num);
|
csum, cb_sum, cb->mirror_num);
|
||||||
if (btrfs_bio(bio)->device)
|
if (btrfs_bio(bio)->device)
|
||||||
|
|
|
@ -3253,6 +3253,8 @@ u64 btrfs_file_extent_end(const struct btrfs_path *path);
|
||||||
/* inode.c */
|
/* inode.c */
|
||||||
void btrfs_submit_data_bio(struct inode *inode, struct bio *bio,
|
void btrfs_submit_data_bio(struct inode *inode, struct bio *bio,
|
||||||
int mirror_num, enum btrfs_compression_type compress_type);
|
int mirror_num, enum btrfs_compression_type compress_type);
|
||||||
|
int btrfs_check_sector_csum(struct btrfs_fs_info *fs_info, struct page *page,
|
||||||
|
u32 pgoff, u8 *csum, const u8 * const csum_expected);
|
||||||
unsigned int btrfs_verify_data_csum(struct btrfs_bio *bbio,
|
unsigned int btrfs_verify_data_csum(struct btrfs_bio *bbio,
|
||||||
u32 bio_offset, struct page *page,
|
u32 bio_offset, struct page *page,
|
||||||
u64 start, u64 end);
|
u64 start, u64 end);
|
||||||
|
|
|
@ -3328,6 +3328,29 @@ void btrfs_writepage_endio_finish_ordered(struct btrfs_inode *inode,
|
||||||
finish_ordered_fn, uptodate);
|
finish_ordered_fn, uptodate);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Verify the checksum for a single sector without any extra action that depend
|
||||||
|
* on the type of I/O.
|
||||||
|
*/
|
||||||
|
int btrfs_check_sector_csum(struct btrfs_fs_info *fs_info, struct page *page,
|
||||||
|
u32 pgoff, u8 *csum, const u8 * const csum_expected)
|
||||||
|
{
|
||||||
|
SHASH_DESC_ON_STACK(shash, fs_info->csum_shash);
|
||||||
|
char *kaddr;
|
||||||
|
|
||||||
|
ASSERT(pgoff + fs_info->sectorsize <= PAGE_SIZE);
|
||||||
|
|
||||||
|
shash->tfm = fs_info->csum_shash;
|
||||||
|
|
||||||
|
kaddr = kmap_local_page(page) + pgoff;
|
||||||
|
crypto_shash_digest(shash, kaddr, fs_info->sectorsize, csum);
|
||||||
|
kunmap_local(kaddr);
|
||||||
|
|
||||||
|
if (memcmp(csum, csum_expected, fs_info->csum_size))
|
||||||
|
return -EIO;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* check_data_csum - verify checksum of one sector of uncompressed data
|
* check_data_csum - verify checksum of one sector of uncompressed data
|
||||||
* @inode: inode
|
* @inode: inode
|
||||||
|
@ -3338,14 +3361,15 @@ void btrfs_writepage_endio_finish_ordered(struct btrfs_inode *inode,
|
||||||
* @start: logical offset in the file
|
* @start: logical offset in the file
|
||||||
*
|
*
|
||||||
* The length of such check is always one sector size.
|
* The length of such check is always one sector size.
|
||||||
|
*
|
||||||
|
* When csum mismatch is detected, we will also report the error and fill the
|
||||||
|
* corrupted range with zero. (Thus it needs the extra parameters)
|
||||||
*/
|
*/
|
||||||
static int check_data_csum(struct inode *inode, struct btrfs_bio *bbio,
|
static int check_data_csum(struct inode *inode, struct btrfs_bio *bbio,
|
||||||
u32 bio_offset, struct page *page, u32 pgoff,
|
u32 bio_offset, struct page *page, u32 pgoff,
|
||||||
u64 start)
|
u64 start)
|
||||||
{
|
{
|
||||||
struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
|
struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
|
||||||
SHASH_DESC_ON_STACK(shash, fs_info->csum_shash);
|
|
||||||
char *kaddr;
|
|
||||||
u32 len = fs_info->sectorsize;
|
u32 len = fs_info->sectorsize;
|
||||||
const u32 csum_size = fs_info->csum_size;
|
const u32 csum_size = fs_info->csum_size;
|
||||||
unsigned int offset_sectors;
|
unsigned int offset_sectors;
|
||||||
|
@ -3357,16 +3381,10 @@ static int check_data_csum(struct inode *inode, struct btrfs_bio *bbio,
|
||||||
offset_sectors = bio_offset >> fs_info->sectorsize_bits;
|
offset_sectors = bio_offset >> fs_info->sectorsize_bits;
|
||||||
csum_expected = ((u8 *)bbio->csum) + offset_sectors * csum_size;
|
csum_expected = ((u8 *)bbio->csum) + offset_sectors * csum_size;
|
||||||
|
|
||||||
kaddr = kmap_atomic(page);
|
if (btrfs_check_sector_csum(fs_info, page, pgoff, csum, csum_expected))
|
||||||
shash->tfm = fs_info->csum_shash;
|
|
||||||
|
|
||||||
crypto_shash_digest(shash, kaddr + pgoff, len, csum);
|
|
||||||
kunmap_atomic(kaddr);
|
|
||||||
|
|
||||||
if (memcmp(csum, csum_expected, csum_size))
|
|
||||||
goto zeroit;
|
goto zeroit;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
zeroit:
|
zeroit:
|
||||||
btrfs_print_data_csum_error(BTRFS_I(inode), start, csum, csum_expected,
|
btrfs_print_data_csum_error(BTRFS_I(inode), start, csum, csum_expected,
|
||||||
bbio->mirror_num);
|
bbio->mirror_num);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue