Commit 80ff5d18 authored by jpsollie's avatar jpsollie Committed by Kent Overstreet

bcachefs: Prepare checksums for more advanced algorithms

Perform abstraction of hash calculation for advanced checksum algorithms.
Algorithms like xxhash do not store their state as a u64 int.
Signed-off-by: default avatarjpsollie <janpieter.sollie@edpnet.be>
Signed-off-by: default avatarKent Overstreet <kent.overstreet@linux.dev>
parent a515d0a5
...@@ -16,53 +16,68 @@ ...@@ -16,53 +16,68 @@
#include <crypto/skcipher.h> #include <crypto/skcipher.h>
#include <keys/user-type.h> #include <keys/user-type.h>
static u64 bch2_checksum_init(unsigned type) /*
* bch2_checksum state is an abstraction of the checksum state calculated over different pages.
* it features page merging without having the checksum algorithm lose its state.
* for native checksum aglorithms (like crc), a default seed value will do.
* for hash-like algorithms, a state needs to be stored
*/
struct bch2_checksum_state {
union {
u64 seed;
};
unsigned int type;
};
static void bch2_checksum_init(struct bch2_checksum_state *state)
{ {
switch (type) { switch (state->type) {
case BCH_CSUM_NONE: case BCH_CSUM_NONE:
return 0;
case BCH_CSUM_CRC32C_NONZERO:
return U32_MAX;
case BCH_CSUM_CRC64_NONZERO:
return U64_MAX;
case BCH_CSUM_CRC32C: case BCH_CSUM_CRC32C:
return 0;
case BCH_CSUM_CRC64: case BCH_CSUM_CRC64:
return 0; state->seed = 0;
break;
case BCH_CSUM_CRC32C_NONZERO:
state->seed = U32_MAX;
break;
case BCH_CSUM_CRC64_NONZERO:
state->seed = U64_MAX;
break;
default: default:
BUG(); BUG();
} }
} }
static u64 bch2_checksum_final(unsigned type, u64 crc) static u64 bch2_checksum_final(const struct bch2_checksum_state *state)
{ {
switch (type) { switch (state->type) {
case BCH_CSUM_NONE: case BCH_CSUM_NONE:
return 0;
case BCH_CSUM_CRC32C_NONZERO:
return crc ^ U32_MAX;
case BCH_CSUM_CRC64_NONZERO:
return crc ^ U64_MAX;
case BCH_CSUM_CRC32C: case BCH_CSUM_CRC32C:
return crc;
case BCH_CSUM_CRC64: case BCH_CSUM_CRC64:
return crc; return state->seed;
case BCH_CSUM_CRC32C_NONZERO:
return state->seed ^ U32_MAX;
case BCH_CSUM_CRC64_NONZERO:
return state->seed ^ U64_MAX;
default: default:
BUG(); BUG();
} }
} }
static u64 bch2_checksum_update(unsigned type, u64 crc, const void *data, size_t len) static void bch2_checksum_update(struct bch2_checksum_state *state, const void *data, size_t len)
{ {
switch (type) { switch (state->type) {
case BCH_CSUM_NONE: case BCH_CSUM_NONE:
return 0; return;
case BCH_CSUM_CRC32C_NONZERO: case BCH_CSUM_CRC32C_NONZERO:
case BCH_CSUM_CRC32C: case BCH_CSUM_CRC32C:
return crc32c(crc, data, len); state->seed = crc32c(state->seed, data, len);
break;
case BCH_CSUM_CRC64_NONZERO: case BCH_CSUM_CRC64_NONZERO:
case BCH_CSUM_CRC64: case BCH_CSUM_CRC64:
return crc64_be(crc, data, len); state->seed = crc64_be(state->seed, data, len);
break;
default: default:
BUG(); BUG();
} }
...@@ -141,12 +156,14 @@ struct bch_csum bch2_checksum(struct bch_fs *c, unsigned type, ...@@ -141,12 +156,14 @@ struct bch_csum bch2_checksum(struct bch_fs *c, unsigned type,
case BCH_CSUM_CRC64_NONZERO: case BCH_CSUM_CRC64_NONZERO:
case BCH_CSUM_CRC32C: case BCH_CSUM_CRC32C:
case BCH_CSUM_CRC64: { case BCH_CSUM_CRC64: {
u64 crc = bch2_checksum_init(type); struct bch2_checksum_state state;
crc = bch2_checksum_update(type, crc, data, len); state.type = type;
crc = bch2_checksum_final(type, crc);
return (struct bch_csum) { .lo = cpu_to_le64(crc) }; bch2_checksum_init(&state);
bch2_checksum_update(&state, data, len);
return (struct bch_csum) { .lo = cpu_to_le64(bch2_checksum_final(&state)) };
} }
case BCH_CSUM_CHACHA20_POLY1305_80: case BCH_CSUM_CHACHA20_POLY1305_80:
...@@ -190,23 +207,23 @@ static struct bch_csum __bch2_checksum_bio(struct bch_fs *c, unsigned type, ...@@ -190,23 +207,23 @@ static struct bch_csum __bch2_checksum_bio(struct bch_fs *c, unsigned type,
case BCH_CSUM_CRC64_NONZERO: case BCH_CSUM_CRC64_NONZERO:
case BCH_CSUM_CRC32C: case BCH_CSUM_CRC32C:
case BCH_CSUM_CRC64: { case BCH_CSUM_CRC64: {
u64 crc = bch2_checksum_init(type); struct bch2_checksum_state state;
state.type = type;
bch2_checksum_init(&state);
#ifdef CONFIG_HIGHMEM #ifdef CONFIG_HIGHMEM
__bio_for_each_segment(bv, bio, *iter, *iter) { __bio_for_each_segment(bv, bio, *iter, *iter) {
void *p = kmap_atomic(bv.bv_page) + bv.bv_offset; void *p = kmap_atomic(bv.bv_page) + bv.bv_offset;
crc = bch2_checksum_update(type, bch2_checksum_update(&state, p, bv.bv_len);
crc, p, bv.bv_len);
kunmap_atomic(p); kunmap_atomic(p);
} }
#else #else
__bio_for_each_bvec(bv, bio, *iter, *iter) __bio_for_each_bvec(bv, bio, *iter, *iter)
crc = bch2_checksum_update(type, crc, bch2_checksum_update(&state, page_address(bv.bv_page) + bv.bv_offset,
page_address(bv.bv_page) + bv.bv_offset,
bv.bv_len); bv.bv_len);
#endif #endif
crc = bch2_checksum_final(type, crc); return (struct bch_csum) { .lo = cpu_to_le64(bch2_checksum_final(&state)) };
return (struct bch_csum) { .lo = cpu_to_le64(crc) };
} }
case BCH_CSUM_CHACHA20_POLY1305_80: case BCH_CSUM_CHACHA20_POLY1305_80:
...@@ -284,16 +301,22 @@ void bch2_encrypt_bio(struct bch_fs *c, unsigned type, ...@@ -284,16 +301,22 @@ void bch2_encrypt_bio(struct bch_fs *c, unsigned type,
struct bch_csum bch2_checksum_merge(unsigned type, struct bch_csum a, struct bch_csum bch2_checksum_merge(unsigned type, struct bch_csum a,
struct bch_csum b, size_t b_len) struct bch_csum b, size_t b_len)
{ {
struct bch2_checksum_state state;
state.type = type;
bch2_checksum_init(&state);
state.seed = a.lo;
BUG_ON(!bch2_checksum_mergeable(type)); BUG_ON(!bch2_checksum_mergeable(type));
while (b_len) { while (b_len) {
unsigned b = min_t(unsigned, b_len, PAGE_SIZE); unsigned b = min_t(unsigned, b_len, PAGE_SIZE);
a.lo = bch2_checksum_update(type, a.lo, bch2_checksum_update(&state,
page_address(ZERO_PAGE(0)), b); page_address(ZERO_PAGE(0)), b);
b_len -= b; b_len -= b;
} }
a.lo = bch2_checksum_final(&state);
a.lo ^= b.lo; a.lo ^= b.lo;
a.hi ^= b.hi; a.hi ^= b.hi;
return a; return a;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment