summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKent Overstreet <kent.overstreet@gmail.com>2016-08-10 07:02:23 -0800
committerKent Overstreet <kent.overstreet@gmail.com>2016-09-15 19:27:28 -0800
commit58e239ee3991422245ececa1e4ca541d83da2438 (patch)
treecfccb6f80559ca63fbd8ee74de629de00dd24b04
parenta5e2d9aaea8435daa0848be5941f563254ab3c3d (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.c44
-rw-r--r--drivers/md/bcache/checksum.h2
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,