From patchwork Fri Dec 19 12:57:06 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Liu Bo X-Patchwork-Id: 5519131 Return-Path: X-Original-To: patchwork-linux-btrfs@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork1.web.kernel.org (Postfix) with ESMTP id 19E719F443 for ; Fri, 19 Dec 2014 12:57:30 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 02F6520125 for ; Fri, 19 Dec 2014 12:57:28 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 8ABB020145 for ; Fri, 19 Dec 2014 12:57:25 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752175AbaLSM5V (ORCPT ); Fri, 19 Dec 2014 07:57:21 -0500 Received: from aserp1040.oracle.com ([141.146.126.69]:45162 "EHLO aserp1040.oracle.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751819AbaLSM5T (ORCPT ); Fri, 19 Dec 2014 07:57:19 -0500 Received: from ucsinet21.oracle.com (ucsinet21.oracle.com [156.151.31.93]) by aserp1040.oracle.com (Sentrion-MTA-4.3.2/Sentrion-MTA-4.3.2) with ESMTP id sBJCvI4h031241 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK) for ; Fri, 19 Dec 2014 12:57:19 GMT Received: from aserz7021.oracle.com (aserz7021.oracle.com [141.146.126.230]) by ucsinet21.oracle.com (8.14.4+Sun/8.14.4) with ESMTP id sBJCvHph009836 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=FAIL) for ; Fri, 19 Dec 2014 12:57:18 GMT Received: from abhmp0005.oracle.com (abhmp0005.oracle.com [141.146.116.11]) by aserz7021.oracle.com (8.14.4+Sun/8.14.4) with ESMTP id sBJCvHdN010342 for ; Fri, 19 Dec 2014 12:57:17 GMT Received: from localhost.localdomain.com (/10.182.228.124) by default (Oracle Beehive Gateway v4.0) with ESMTP ; Fri, 19 Dec 2014 04:57:16 -0800 From: Liu Bo To: linux-btrfs@vger.kernel.org Subject: [PATCH] Btrfs: generic checksum framework Date: Fri, 19 Dec 2014 20:57:06 +0800 Message-Id: <1418993826-13824-1-git-send-email-bo.li.liu@oracle.com> X-Mailer: git-send-email 1.8.1.4 X-Source-IP: ucsinet21.oracle.com [156.151.31.93] Sender: linux-btrfs-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-btrfs@vger.kernel.org X-Spam-Status: No, score=-6.9 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_HI, T_RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP This changes the original crc32c specific checksum functions into more generic ones, so that converting to a new checksum algorithm can be transparent to btrfs internal code. Note that file names' lookup and extent_data_ref's hashing use crc32c with their own seed instead of the default "~0", so they remain unchanged. Signed-off-by: Liu Bo --- fs/btrfs/check-integrity.c | 10 +++-- fs/btrfs/compression.c | 30 ++++++------- fs/btrfs/ctree.h | 5 ++- fs/btrfs/disk-io.c | 100 +++++++++++++++++++++++--------------------- fs/btrfs/disk-io.h | 2 - fs/btrfs/file-item.c | 25 +++++------ fs/btrfs/free-space-cache.c | 8 ++-- fs/btrfs/hash.c | 49 ++++++++++++++++++++++ fs/btrfs/hash.h | 9 +++- fs/btrfs/inode.c | 21 ++++++---- fs/btrfs/ioctl.c | 1 + fs/btrfs/ordered-data.c | 10 +++-- fs/btrfs/ordered-data.h | 9 ++-- fs/btrfs/scrub.c | 55 +++++++++++++++++------- 14 files changed, 216 insertions(+), 118 deletions(-) diff --git a/fs/btrfs/check-integrity.c b/fs/btrfs/check-integrity.c index d897ef8..4c26cfa 100644 --- a/fs/btrfs/check-integrity.c +++ b/fs/btrfs/check-integrity.c @@ -1790,8 +1790,8 @@ static int btrfsic_test_for_metadata(struct btrfsic_state *state, { struct btrfs_header *h; u8 csum[BTRFS_CSUM_SIZE]; - u32 crc = ~(u32)0; unsigned int i; + SHASH_DESC_ON_STACK(shash, state->root->fs_info->csum_tfm); if (num_pages * PAGE_CACHE_SIZE < state->metablock_size) return 1; /* not metadata */ @@ -1801,14 +1801,18 @@ static int btrfsic_test_for_metadata(struct btrfsic_state *state, if (memcmp(h->fsid, state->root->fs_info->fsid, BTRFS_UUID_SIZE)) return 1; + shash->tfm = state->root->fs_info->csum_tfm; + shash->flags = 0; + crypto_shash_init(shash); + for (i = 0; i < num_pages; i++) { u8 *data = i ? datav[i] : (datav[i] + BTRFS_CSUM_SIZE); size_t sublen = i ? PAGE_CACHE_SIZE : (PAGE_CACHE_SIZE - BTRFS_CSUM_SIZE); - crc = btrfs_crc32c(crc, data, sublen); + crypto_shash_update(shash, data, sublen); } - btrfs_csum_final(crc, csum); + crypto_shash_final(shash, csum); if (memcmp(csum, h->csum, state->csum_size)) return 1; diff --git a/fs/btrfs/compression.c b/fs/btrfs/compression.c index e9df886..42c2435 100644 --- a/fs/btrfs/compression.c +++ b/fs/btrfs/compression.c @@ -78,7 +78,7 @@ struct compressed_bio { * the start of a variable length array of checksums only * used by reads */ - u32 sums; + u8 sums[]; }; static int btrfs_decompress_biovec(int type, struct page **pages_in, @@ -111,31 +111,29 @@ static int check_compressed_csum(struct inode *inode, struct page *page; unsigned long i; char *kaddr; - u32 csum; - u32 *cb_sum = &cb->sums; + u8 csum[BTRFS_CSUM_SIZE]; + u8 *cb_sum = cb->sums; + struct btrfs_fs_info *fs_info = BTRFS_I(inode)->root->fs_info; + u16 csum_size = btrfs_super_csum_size(fs_info->super_copy); if (BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM) return 0; for (i = 0; i < cb->nr_pages; i++) { page = cb->compressed_pages[i]; - csum = ~(u32)0; kaddr = kmap_atomic(page); - csum = btrfs_csum_data(kaddr, csum, PAGE_CACHE_SIZE); - btrfs_csum_final(csum, (char *)&csum); + btrfs_csum(fs_info, kaddr, PAGE_CACHE_SIZE, csum); kunmap_atomic(kaddr); - if (csum != *cb_sum) { + if (memcmp(csum, cb_sum, csum_size)) { btrfs_info(BTRFS_I(inode)->root->fs_info, - "csum failed ino %llu extent %llu csum %u wanted %u mirror %d", - btrfs_ino(inode), disk_start, csum, *cb_sum, - cb->mirror_num); + "csum failed ino %llu extent %llu mirror %d", + btrfs_ino(inode), disk_start, cb->mirror_num); ret = -EIO; goto fail; } - cb_sum++; - + cb_sum += csum_size; } ret = 0; fail: @@ -584,7 +582,8 @@ int btrfs_submit_compressed_read(struct inode *inode, struct bio *bio, struct extent_map *em; int ret = -ENOMEM; int faili = 0; - u32 *sums; + u8 *sums; + u16 csum_size = btrfs_super_csum_size(root->fs_info->super_copy); tree = &BTRFS_I(inode)->io_tree; em_tree = &BTRFS_I(inode)->extent_tree; @@ -607,7 +606,7 @@ int 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; @@ -692,7 +691,8 @@ int btrfs_submit_compressed_read(struct inode *inode, struct bio *bio, comp_bio, sums); BUG_ON(ret); /* -ENOMEM */ } - sums += DIV_ROUND_UP(comp_bio->bi_iter.bi_size, + sums += csum_size * + DIV_ROUND_UP(comp_bio->bi_iter.bi_size, root->sectorsize); ret = btrfs_map_bio(root, READ, comp_bio, diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index e6fbbd7..be47b10 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -38,6 +38,7 @@ #include "extent_io.h" #include "extent_map.h" #include "async-thread.h" +#include "hash.h" struct btrfs_trans_handle; struct btrfs_transaction; @@ -1749,6 +1750,8 @@ struct btrfs_fs_info { * and will be latter freed. Protected by fs_info->chunk_mutex. */ struct list_head pinned_chunks; + + struct crypto_shash *csum_tfm; }; struct btrfs_subvolume_writers { @@ -3796,7 +3799,7 @@ struct btrfs_dio_private; int btrfs_del_csums(struct btrfs_trans_handle *trans, struct btrfs_root *root, u64 bytenr, u64 len); int btrfs_lookup_bio_sums(struct btrfs_root *root, struct inode *inode, - struct bio *bio, u32 *dst); + struct bio *bio, u8 *dst); int btrfs_lookup_bio_sums_dio(struct btrfs_root *root, struct inode *inode, struct bio *bio, u64 logical_offset); int btrfs_insert_file_extent(struct btrfs_trans_handle *trans, diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 3096512..b16d37e 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -260,16 +260,6 @@ out: return em; } -u32 btrfs_csum_data(char *data, u32 seed, size_t len) -{ - return btrfs_crc32c(seed, data, len); -} - -void btrfs_csum_final(u32 crc, char *result) -{ - put_unaligned_le32(~crc, result); -} - /* * compute the csum for a btree block, and either verify it or write it * into the csum field of the block. @@ -286,8 +276,13 @@ static int csum_tree_block(struct btrfs_root *root, struct extent_buffer *buf, unsigned long map_start; unsigned long map_len; int err; - u32 crc = ~(u32)0; unsigned long inline_result; + SHASH_DESC_ON_STACK(shash, root->fs_info->csum_tfm); + + shash->tfm = root->fs_info->csum_tfm; + shash->flags = 0; + + crypto_shash_init(shash); len = buf->len - offset; while (len > 0) { @@ -296,8 +291,9 @@ static int csum_tree_block(struct btrfs_root *root, struct extent_buffer *buf, if (err) return 1; cur_len = min(len, map_len - (offset - map_start)); - crc = btrfs_csum_data(kaddr + offset - map_start, - crc, cur_len); + crypto_shash_update(shash, kaddr + offset - map_start, + cur_len); + len -= cur_len; offset += cur_len; } @@ -309,7 +305,7 @@ static int csum_tree_block(struct btrfs_root *root, struct extent_buffer *buf, result = (char *)&inline_result; } - btrfs_csum_final(crc, result); + crypto_shash_final(shash, result); if (verify) { if (memcmp_extent_buffer(buf, result, 0, csum_size)) { @@ -319,10 +315,10 @@ static int csum_tree_block(struct btrfs_root *root, struct extent_buffer *buf, read_extent_buffer(buf, &val, 0, csum_size); printk_ratelimited(KERN_INFO - "BTRFS: %s checksum verify failed on %llu wanted %X found %X " + "BTRFS: %s checksum verify failed on %llu wanted found " "level %d\n", root->fs_info->sb->s_id, buf->start, - val, found, btrfs_header_level(buf)); + btrfs_header_level(buf)); if (result != (char *)&inline_result) kfree(result); return 1; @@ -394,41 +390,42 @@ out: * Return 0 if the superblock checksum type matches the checksum value of that * algorithm. Pass the raw disk superblock data. */ -static int btrfs_check_super_csum(char *raw_disk_sb) +static int btrfs_check_super_csum(struct btrfs_fs_info *info, char *raw_disk_sb) { struct btrfs_super_block *disk_sb = (struct btrfs_super_block *)raw_disk_sb; u16 csum_type = btrfs_super_csum_type(disk_sb); + const int csum_size = btrfs_super_csum_size(disk_sb); + char result[csum_size]; int ret = 0; - if (csum_type == BTRFS_CSUM_TYPE_CRC32) { - u32 crc = ~(u32)0; - const int csum_size = sizeof(crc); - char result[csum_size]; + if (csum_type >= ARRAY_SIZE(btrfs_csum_sizes)) { + pr_err("BTRFS: unsupported checksum algorithm %u\n", + csum_type); + return 1; + } - /* - * The super_block structure does not span the whole - * BTRFS_SUPER_INFO_SIZE range, we expect that the unused space - * is filled with zeros and is included in the checkum. - */ - crc = btrfs_csum_data(raw_disk_sb + BTRFS_CSUM_SIZE, - crc, BTRFS_SUPER_INFO_SIZE - BTRFS_CSUM_SIZE); - btrfs_csum_final(crc, result); + btrfs_csum(info, raw_disk_sb + BTRFS_CSUM_SIZE, + BTRFS_SUPER_INFO_SIZE - BTRFS_CSUM_SIZE, result); - if (memcmp(raw_disk_sb, result, csum_size)) - ret = 1; + if (memcmp(raw_disk_sb, result, csum_size)) + ret = 1; - if (ret && btrfs_super_generation(disk_sb) < 10) { - printk(KERN_WARNING - "BTRFS: super block crcs don't match, older mkfs detected\n"); - ret = 0; - } + if (ret && btrfs_super_generation(disk_sb) < 10) { + pr_warn("BTRFS: super block crcs don't match, older mkfs detected\n"); + ret = 0; } - if (csum_type >= ARRAY_SIZE(btrfs_csum_sizes)) { - printk(KERN_ERR "BTRFS: unsupported checksum algorithm %u\n", + if (!ret) { + switch (csum_type) { + case 0: + btrfs_info(info, "crc32c is the checksum algorithm."); + break; + default: + WARN(1, "Btrfs: unsupported checksum algorithm %u.\n", csum_type); - ret = 1; + break; + } } return ret; @@ -2406,11 +2403,22 @@ int open_ctree(struct super_block *sb, goto fail_alloc; } + { + u16 csum_type = btrfs_super_csum_type( + (struct btrfs_super_block *)bh->b_data); + + if (btrfs_csum_init(fs_info, csum_type)) { + err = -EINVAL; + pr_err("BTRFS: csum init error\n"); + goto fail_alloc; + } + } + /* * We want to check superblock checksum, the type is stored inside. * Pass the whole disk block of size BTRFS_SUPER_INFO_SIZE (4k). */ - if (btrfs_check_super_csum(bh->b_data)) { + if (btrfs_check_super_csum(fs_info, bh->b_data)) { printk(KERN_ERR "BTRFS: superblock checksum mismatch\n"); err = -EINVAL; goto fail_alloc; @@ -3014,6 +3022,7 @@ fail_tree_roots: fail_sb_buffer: btrfs_stop_all_workers(fs_info); fail_alloc: + btrfs_csum_exit(fs_info); fail_iput: btrfs_mapping_tree_free(&fs_info->mapping_tree); @@ -3134,7 +3143,6 @@ static int write_dev_supers(struct btrfs_device *device, int i; int ret; int errors = 0; - u32 crc; u64 bytenr; if (max_mirrors == 0) @@ -3166,12 +3174,10 @@ static int write_dev_supers(struct btrfs_device *device, } else { btrfs_set_super_bytenr(sb, bytenr); - crc = ~(u32)0; - crc = btrfs_csum_data((char *)sb + - BTRFS_CSUM_SIZE, crc, - BTRFS_SUPER_INFO_SIZE - - BTRFS_CSUM_SIZE); - btrfs_csum_final(crc, sb->csum); + btrfs_csum(device->dev_root->fs_info, + (char *)sb + BTRFS_CSUM_SIZE, + BTRFS_SUPER_INFO_SIZE - BTRFS_CSUM_SIZE, + sb->csum); /* * one reference for us, and we leave it for the diff --git a/fs/btrfs/disk-io.h b/fs/btrfs/disk-io.h index 4146518..e8bbb96 100644 --- a/fs/btrfs/disk-io.h +++ b/fs/btrfs/disk-io.h @@ -116,8 +116,6 @@ int btrfs_buffer_uptodate(struct extent_buffer *buf, u64 parent_transid, int atomic); int btrfs_set_buffer_uptodate(struct extent_buffer *buf); int btrfs_read_buffer(struct extent_buffer *buf, u64 parent_transid); -u32 btrfs_csum_data(char *data, u32 seed, size_t len); -void btrfs_csum_final(u32 crc, char *result); int btrfs_bio_wq_end_io(struct btrfs_fs_info *info, struct bio *bio, enum btrfs_wq_endio_type metadata); int btrfs_wq_submit_bio(struct btrfs_fs_info *fs_info, struct inode *inode, diff --git a/fs/btrfs/file-item.c b/fs/btrfs/file-item.c index 84a2d18..d777c50 100644 --- a/fs/btrfs/file-item.c +++ b/fs/btrfs/file-item.c @@ -33,9 +33,9 @@ #define MAX_CSUM_ITEMS(r, size) (min_t(u32, __MAX_CSUM_ITEMS(r, size), \ PAGE_CACHE_SIZE)) -#define MAX_ORDERED_SUM_BYTES(r) ((PAGE_SIZE - \ +#define MAX_ORDERED_SUM_BYTES(r, size) ((PAGE_SIZE - \ sizeof(struct btrfs_ordered_sum)) / \ - sizeof(u32) * (r)->sectorsize) + sizeof(u8) * size * (r)->sectorsize) int btrfs_insert_file_extent(struct btrfs_trans_handle *trans, struct btrfs_root *root, @@ -160,7 +160,7 @@ static void btrfs_io_bio_endio_readpage(struct btrfs_io_bio *bio, int err) static int __btrfs_lookup_bio_sums(struct btrfs_root *root, struct inode *inode, struct bio *bio, - u64 logical_offset, u32 *dst, int dio) + u64 logical_offset, u8 *dst, int dio) { struct bio_vec *bvec = bio->bi_io_vec; struct btrfs_io_bio *btrfs_bio = btrfs_io_bio(bio); @@ -224,7 +224,7 @@ static int __btrfs_lookup_bio_sums(struct btrfs_root *root, 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; @@ -293,7 +293,7 @@ found: } int btrfs_lookup_bio_sums(struct btrfs_root *root, struct inode *inode, - struct bio *bio, u32 *dst) + struct bio *bio, u8 *dst) { return __btrfs_lookup_bio_sums(root, inode, bio, 0, dst, 0); } @@ -384,7 +384,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(root)); + MAX_ORDERED_SUM_BYTES(root, csum_size)); sums = kzalloc(btrfs_ordered_sum_size(root, size), GFP_NOFS); if (!sums) { @@ -435,6 +435,7 @@ int btrfs_csum_one_bio(struct btrfs_root *root, struct inode *inode, unsigned long total_bytes = 0; unsigned long this_sum_bytes = 0; u64 offset; + u16 csum_size = btrfs_super_csum_size(root->fs_info->super_copy); WARN_ON(bio->bi_vcnt <= 0); sums = kzalloc(btrfs_ordered_sum_size(root, bio->bi_iter.bi_size), @@ -481,16 +482,12 @@ int btrfs_csum_one_bio(struct btrfs_root *root, struct inode *inode, } data = kmap_atomic(bvec->bv_page); - sums->sums[index] = ~(u32)0; - sums->sums[index] = btrfs_csum_data(data + bvec->bv_offset, - sums->sums[index], - bvec->bv_len); + btrfs_csum(root->fs_info, data + bvec->bv_offset, + bvec->bv_len, sums->sums + index); kunmap_atomic(data); - btrfs_csum_final(sums->sums[index], - (char *)(sums->sums + index)); bio_index++; - index++; + index += csum_size; total_bytes += bvec->bv_len; this_sum_bytes += bvec->bv_len; offset += bvec->bv_len; @@ -858,9 +855,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 * root->sectorsize; - index += ins_size; btrfs_mark_buffer_dirty(path->nodes[0]); if (total_bytes < sums->len) { diff --git a/fs/btrfs/free-space-cache.c b/fs/btrfs/free-space-cache.c index 030847b..448cf6f 100644 --- a/fs/btrfs/free-space-cache.c +++ b/fs/btrfs/free-space-cache.c @@ -449,9 +449,9 @@ static void io_ctl_set_crc(struct io_ctl *io_ctl, int index) if (index == 0) offset = sizeof(u32) * io_ctl->num_pages; - crc = btrfs_csum_data(io_ctl->orig + offset, crc, + crc = btrfs_crc32c(crc, io_ctl->orig + offset, PAGE_CACHE_SIZE - offset); - btrfs_csum_final(crc, (char *)&crc); + btrfs_crc32c_final(crc, (char *)&crc); io_ctl_unmap_page(io_ctl); tmp = kmap(io_ctl->pages[0]); tmp += index; @@ -479,9 +479,9 @@ static int io_ctl_check_crc(struct io_ctl *io_ctl, int index) kunmap(io_ctl->pages[0]); io_ctl_map_page(io_ctl, 0); - crc = btrfs_csum_data(io_ctl->orig + offset, crc, + crc = btrfs_crc32c(crc, io_ctl->orig + offset, PAGE_CACHE_SIZE - offset); - btrfs_csum_final(crc, (char *)&crc); + btrfs_crc32c_final(crc, (char *)&crc); if (val != crc) { printk_ratelimited(KERN_ERR "BTRFS: csum mismatch on free " "space cache\n"); diff --git a/fs/btrfs/hash.c b/fs/btrfs/hash.c index aae520b..9145ad8 100644 --- a/fs/btrfs/hash.c +++ b/fs/btrfs/hash.c @@ -13,6 +13,7 @@ #include #include +#include #include "hash.h" static struct crypto_shash *tfm; @@ -29,6 +30,7 @@ void btrfs_hash_exit(void) crypto_free_shash(tfm); } +/* btrfs_name_hash() still needs this. */ u32 btrfs_crc32c(u32 crc, const void *address, unsigned int length) { SHASH_DESC_ON_STACK(shash, tfm); @@ -44,3 +46,50 @@ u32 btrfs_crc32c(u32 crc, const void *address, unsigned int length) return *ctx; } + +void btrfs_crc32c_final(u32 crc, char *result) +{ + put_unaligned_le32(~crc, result); +} + +int btrfs_csum_init(struct btrfs_fs_info *info, u16 csum_type) +{ + struct crypto_shash *tfm = NULL; + + switch (csum_type) { + case BTRFS_CSUM_TYPE_CRC32: + tfm = crypto_alloc_shash("crc32c", 0, 0); + break; + default: + pr_err("Btrfs: checksum type %d is not supported\n", + csum_type); + break; + } + + if (IS_ERR(tfm)) + return PTR_ERR(tfm); + + info->csum_tfm = tfm; + return 0; +} + +void btrfs_csum_exit(struct btrfs_fs_info *info) +{ + if (info->csum_tfm) + crypto_free_shash(info->csum_tfm); +} + +int btrfs_csum(struct btrfs_fs_info *info, const void *address, + unsigned int length, u8 *out) +{ + SHASH_DESC_ON_STACK(shash, info->csum_tfm); + int err; + + shash->tfm = info->csum_tfm; + shash->flags = 0; + + err = crypto_shash_digest(shash, address, length, out); + + ASSERT(!err); + return err; +} diff --git a/fs/btrfs/hash.h b/fs/btrfs/hash.h index 118a231..cfa896f 100644 --- a/fs/btrfs/hash.h +++ b/fs/btrfs/hash.h @@ -19,11 +19,14 @@ #ifndef __HASH__ #define __HASH__ -int __init btrfs_hash_init(void); +#include +#include "ctree.h" +int __init btrfs_hash_init(void); void btrfs_hash_exit(void); u32 btrfs_crc32c(u32 crc, const void *address, unsigned int length); +void btrfs_crc32c_final(u32 crc, char *result); static inline u64 btrfs_name_hash(const char *name, int len) { @@ -39,4 +42,8 @@ static inline u64 btrfs_extref_hash(u64 parent_objectid, const char *name, return (u64) btrfs_crc32c(parent_objectid, name, len); } +int btrfs_csum_init(struct btrfs_fs_info *fs_info, u16 csum_type); +void btrfs_csum_exit(struct btrfs_fs_info *fs_info); +int btrfs_csum(struct btrfs_fs_info *info, const void *address, + unsigned int length, u8 *out); #endif diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index e687bb0..a46ceed 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -2928,17 +2928,18 @@ static int __readpage_endio_check(struct inode *inode, int pgoff, u64 start, size_t len) { char *kaddr; - u32 csum_expected; - u32 csum = ~(u32)0; + struct btrfs_root *root = BTRFS_I(inode)->root; + u8 *csum_expected; + u8 csum[BTRFS_CSUM_SIZE]; + u16 csum_size = btrfs_super_csum_size(root->fs_info->super_copy); static DEFINE_RATELIMIT_STATE(_rs, DEFAULT_RATELIMIT_INTERVAL, DEFAULT_RATELIMIT_BURST); - csum_expected = *(((u32 *)io_bio->csum) + icsum); + csum_expected = ((u8 *)io_bio->csum) + icsum * csum_size; kaddr = kmap_atomic(page); - csum = btrfs_csum_data(kaddr + pgoff, csum, len); - btrfs_csum_final(csum, (char *)&csum); - if (csum != csum_expected) + btrfs_csum(root->fs_info, kaddr + pgoff, len, csum); + if (memcmp(csum, csum_expected, csum_size)) goto zeroit; kunmap_atomic(kaddr); @@ -2946,13 +2947,17 @@ static int __readpage_endio_check(struct inode *inode, zeroit: if (__ratelimit(&_rs)) btrfs_info(BTRFS_I(inode)->root->fs_info, - "csum failed ino %llu off %llu csum %u expected csum %u", - btrfs_ino(inode), start, csum, csum_expected); + "csum failed ino %llu off %llu", + btrfs_ino(inode), start); memset(kaddr + pgoff, 1, len); flush_dcache_page(page); kunmap_atomic(kaddr); + +/* + * Liubo: Not sure why this could happen. if (csum_expected == 0) return 0; +*/ return -EIO; } diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index d49fe8a..f6e1656 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c @@ -2510,6 +2510,7 @@ out_up_write: iput(dest->ino_cache_inode); dest->ino_cache_inode = NULL; } + wake_up_process(root->fs_info->cleaner_kthread); } out_dput: dput(dentry); diff --git a/fs/btrfs/ordered-data.c b/fs/btrfs/ordered-data.c index 534544e..bb44240 100644 --- a/fs/btrfs/ordered-data.c +++ b/fs/btrfs/ordered-data.c @@ -991,7 +991,7 @@ 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_ordered_sum *ordered_sum; struct btrfs_ordered_extent *ordered; @@ -1000,6 +1000,8 @@ int btrfs_find_ordered_sum(struct inode *inode, u64 offset, u64 disk_bytenr, unsigned long i; u32 sectorsize = BTRFS_I(inode)->root->sectorsize; int index = 0; + u16 csum_size = btrfs_super_csum_size( + BTRFS_I(inode)->root->fs_info->super_copy); ordered = btrfs_lookup_ordered_extent(inode, offset); if (!ordered) @@ -1014,10 +1016,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; diff --git a/fs/btrfs/ordered-data.h b/fs/btrfs/ordered-data.h index e96cd4c..6c4f217 100644 --- a/fs/btrfs/ordered-data.h +++ b/fs/btrfs/ordered-data.h @@ -36,7 +36,7 @@ struct btrfs_ordered_sum { int len; struct list_head list; /* last field is a variable length array of csums */ - u32 sums[]; + u8 sums[]; }; /* @@ -150,7 +150,10 @@ static inline int btrfs_ordered_sum_size(struct btrfs_root *root, unsigned long bytes) { int num_sectors = (int)DIV_ROUND_UP(bytes, root->sectorsize); - return sizeof(struct btrfs_ordered_sum) + num_sectors * sizeof(u32); + int csum_size = btrfs_super_csum_size(root->fs_info->super_copy); + + return sizeof(struct btrfs_ordered_sum) + + num_sectors * sizeof(u8) * csum_size; } static inline void @@ -194,7 +197,7 @@ struct btrfs_ordered_extent *btrfs_lookup_ordered_range(struct inode *inode, 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); int btrfs_wait_ordered_extents(struct btrfs_root *root, int nr); void btrfs_wait_ordered_roots(struct btrfs_fs_info *fs_info, int nr); void btrfs_get_logged_extents(struct inode *inode, diff --git a/fs/btrfs/scrub.c b/fs/btrfs/scrub.c index f2bb13a..8dcdb29 100644 --- a/fs/btrfs/scrub.c +++ b/fs/btrfs/scrub.c @@ -1565,8 +1565,13 @@ static void scrub_recheck_block_checksum(struct btrfs_fs_info *fs_info, { int page_num; u8 calculated_csum[BTRFS_CSUM_SIZE]; - u32 crc = ~(u32)0; void *mapped_buffer; + SHASH_DESC_ON_STACK(shash, fs_info->csum_tfm); + + shash->tfm = fs_info->csum_tfm; + shash->flags = 0; + + crypto_shash_init(shash); WARN_ON(!sblock->pagev[0]->page); if (is_metadata) { @@ -1594,11 +1599,12 @@ static void scrub_recheck_block_checksum(struct btrfs_fs_info *fs_info, for (page_num = 0;;) { if (page_num == 0 && is_metadata) - crc = btrfs_csum_data( - ((u8 *)mapped_buffer) + BTRFS_CSUM_SIZE, - crc, PAGE_SIZE - BTRFS_CSUM_SIZE); + crypto_shash_update(shash, + ((u8 *)mapped_buffer) + BTRFS_CSUM_SIZE, + PAGE_SIZE - BTRFS_CSUM_SIZE); else - crc = btrfs_csum_data(mapped_buffer, crc, PAGE_SIZE); + crypto_shash_update(shash, mapped_buffer, + PAGE_SIZE); kunmap_atomic(mapped_buffer); page_num++; @@ -1609,7 +1615,7 @@ static void scrub_recheck_block_checksum(struct btrfs_fs_info *fs_info, mapped_buffer = kmap_atomic(sblock->pagev[page_num]->page); } - btrfs_csum_final(crc, calculated_csum); + crypto_shash_final(shash, calculated_csum); if (memcmp(calculated_csum, csum, csum_size)) sblock->checksum_error = 1; } @@ -1877,14 +1883,20 @@ static int scrub_checksum(struct scrub_block *sblock) static int scrub_checksum_data(struct scrub_block *sblock) { struct scrub_ctx *sctx = sblock->sctx; + struct btrfs_fs_info *fs_info = sctx->dev_root->fs_info; u8 csum[BTRFS_CSUM_SIZE]; u8 *on_disk_csum; struct page *page; void *buffer; - u32 crc = ~(u32)0; int fail = 0; u64 len; int index; + SHASH_DESC_ON_STACK(shash, fs_info->csum_tfm); + + shash->tfm = fs_info->csum_tfm; + shash->flags = 0; + + crypto_shash_init(shash); BUG_ON(sblock->page_count < 1); if (!sblock->pagev[0]->have_csum) @@ -1899,7 +1911,7 @@ static int scrub_checksum_data(struct scrub_block *sblock) for (;;) { u64 l = min_t(u64, len, PAGE_SIZE); - crc = btrfs_csum_data(buffer, crc, l); + crypto_shash_update(shash, buffer, l); kunmap_atomic(buffer); len -= l; if (len == 0) @@ -1911,7 +1923,7 @@ static int scrub_checksum_data(struct scrub_block *sblock) buffer = kmap_atomic(page); } - btrfs_csum_final(crc, csum); + crypto_shash_final(shash, csum); if (memcmp(csum, on_disk_csum, sctx->csum_size)) fail = 1; @@ -1930,11 +1942,16 @@ static int scrub_checksum_tree_block(struct scrub_block *sblock) void *mapped_buffer; u64 mapped_size; void *p; - u32 crc = ~(u32)0; int fail = 0; int crc_fail = 0; u64 len; int index; + SHASH_DESC_ON_STACK(shash, fs_info->csum_tfm); + + shash->tfm = fs_info->csum_tfm; + shash->flags = 0; + + crypto_shash_init(shash); BUG_ON(sblock->page_count < 1); page = sblock->pagev[0]->page; @@ -1968,7 +1985,7 @@ static int scrub_checksum_tree_block(struct scrub_block *sblock) for (;;) { u64 l = min_t(u64, len, mapped_size); - crc = btrfs_csum_data(p, crc, l); + crypto_shash_update(shash, p, l); kunmap_atomic(mapped_buffer); len -= l; if (len == 0) @@ -1982,7 +1999,7 @@ static int scrub_checksum_tree_block(struct scrub_block *sblock) p = mapped_buffer; } - btrfs_csum_final(crc, calculated_csum); + crypto_shash_final(shash, calculated_csum); if (memcmp(calculated_csum, on_disk_csum, sctx->csum_size)) ++crc_fail; @@ -1993,17 +2010,23 @@ static int scrub_checksum_super(struct scrub_block *sblock) { struct btrfs_super_block *s; struct scrub_ctx *sctx = sblock->sctx; + struct btrfs_fs_info *fs_info = sctx->dev_root->fs_info; u8 calculated_csum[BTRFS_CSUM_SIZE]; u8 on_disk_csum[BTRFS_CSUM_SIZE]; struct page *page; void *mapped_buffer; u64 mapped_size; void *p; - u32 crc = ~(u32)0; int fail_gen = 0; int fail_cor = 0; u64 len; int index; + SHASH_DESC_ON_STACK(shash, fs_info->csum_tfm); + + shash->tfm = fs_info->csum_tfm; + shash->flags = 0; + + crypto_shash_init(shash); BUG_ON(sblock->page_count < 1); page = sblock->pagev[0]->page; @@ -2027,7 +2050,7 @@ static int scrub_checksum_super(struct scrub_block *sblock) for (;;) { u64 l = min_t(u64, len, mapped_size); - crc = btrfs_csum_data(p, crc, l); + crypto_shash_update(shash, p, l); kunmap_atomic(mapped_buffer); len -= l; if (len == 0) @@ -2041,7 +2064,7 @@ static int scrub_checksum_super(struct scrub_block *sblock) p = mapped_buffer; } - btrfs_csum_final(crc, calculated_csum); + crypto_shash_final(shash, calculated_csum); if (memcmp(calculated_csum, on_disk_csum, sctx->csum_size)) ++fail_cor; @@ -2427,7 +2450,7 @@ static int scrub_find_csum(struct scrub_ctx *sctx, u64 logical, u64 len, index = ((u32)(logical - sum->bytenr)) / sctx->sectorsize; num_sectors = sum->len / sctx->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);