diff options
author | Kent Overstreet <kent.overstreet@gmail.com> | 2016-08-10 07:02:23 -0800 |
---|---|---|
committer | Kent Overstreet <kent.overstreet@gmail.com> | 2016-10-07 12:37:06 -0800 |
commit | 9db33be8aabf1282e25ea2efa40d335167123c98 (patch) | |
tree | 98d5a93d734d7dfb168ff352ee8974533b457085 | |
parent | 6cb4e876e4806718f46b2125dd8866f4735d54df (diff) |
bcache: fix 64 bit crc truncation
Note: this is effectively an on disk format change, but it turns out crc64 for
data checksums was just broken before.
-rw-r--r-- | drivers/md/bcache/checksum.c | 44 | ||||
-rw-r--r-- | drivers/md/bcache/checksum.h | 2 |
2 files changed, 37 insertions, 9 deletions
diff --git a/drivers/md/bcache/checksum.c b/drivers/md/bcache/checksum.c index beae0b26e570..b618f08e3b63 100644 --- a/drivers/md/bcache/checksum.c +++ b/drivers/md/bcache/checksum.c @@ -129,6 +129,34 @@ u64 bch_crc64_update(u64 crc, const void *_data, size_t len) return crc; } +static u64 bch_checksum_init(unsigned type) +{ + switch (type) { + case BCH_CSUM_NONE: + return 0; + case BCH_CSUM_CRC32C: + return U32_MAX; + case BCH_CSUM_CRC64: + return U64_MAX; + default: + BUG(); + } +} + +static u64 bch_checksum_final(unsigned type, u64 crc) +{ + switch (type) { + case BCH_CSUM_NONE: + return 0; + case BCH_CSUM_CRC32C: + return crc ^ U32_MAX; + case BCH_CSUM_CRC64: + return crc ^ U64_MAX; + default: + BUG(); + } +} + u64 bch_checksum_update(unsigned type, u64 crc, const void *data, size_t len) { switch (type) { @@ -145,18 +173,18 @@ u64 bch_checksum_update(unsigned type, u64 crc, const void *data, size_t len) u64 bch_checksum(unsigned type, const void *data, size_t len) { - u64 crc = 0xffffffffffffffffULL; + u64 crc = bch_checksum_init(type); crc = bch_checksum_update(type, crc, data, len); - return crc ^ 0xffffffffffffffffULL; + return bch_checksum_final(type, crc); } -u32 bch_checksum_bio(struct bio *bio, unsigned type) +u64 bch_checksum_bio(struct bio *bio, unsigned type) { struct bio_vec bv; struct bvec_iter iter; - u32 csum = U32_MAX; + u64 crc = bch_checksum_init(type); if (type == BCH_CSUM_NONE) return 0; @@ -164,11 +192,11 @@ u32 bch_checksum_bio(struct bio *bio, unsigned type) bio_for_each_segment(bv, bio, iter) { void *p = kmap_atomic(bv.bv_page); - csum = bch_checksum_update(type, csum, - p + bv.bv_offset, - bv.bv_len); + crc = bch_checksum_update(type, crc, + p + bv.bv_offset, + bv.bv_len); kunmap_atomic(p); } - return csum ^= U32_MAX; + return bch_checksum_final(type, crc); } diff --git a/drivers/md/bcache/checksum.h b/drivers/md/bcache/checksum.h index 169a24a527a8..f84f9884d466 100644 --- a/drivers/md/bcache/checksum.h +++ b/drivers/md/bcache/checksum.h @@ -5,7 +5,7 @@ u64 bch_crc64_update(uint64_t, const void *, size_t); u64 bch_checksum_update(unsigned, u64, const void *, size_t); u64 bch_checksum(unsigned, const void *, size_t); -u32 bch_checksum_bio(struct bio *, unsigned); +u64 bch_checksum_bio(struct bio *, unsigned); /* * This is used for various on disk data structures - cache_sb, prio_set, bset, |