--- /dev/null
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+
+#ifndef CEPH_OS_BLUESTORE_CHECKSUMMER
+#define CEPH_OS_BLUESTORE_CHECKSUMMER
+
+#include "include/buffer.h"
+#include "xxHash/xxhash.h"
+#include "bluestore_types.h"
+
+class Checksummer {
+
+ struct crc32c {
+ typedef __le32 value_t;
+
+ // we have no execution context/state.
+ typedef int state_t;
+ static void init(state_t *state) {
+ }
+ static void fini(state_t *state) {
+ }
+
+ static value_t calc(
+ state_t state,
+ size_t len,
+ bufferlist::const_iterator& p
+ ) {
+ bufferlist t;
+ p.copy(len, t);
+ return t.crc32c(-1);
+ }
+ };
+
+ struct xxhash32 {
+ typedef __le32 value_t;
+
+ typedef XXH32_state_t *state_t;
+ static void init(state_t *s) {
+ *s = XXH32_createState();
+ }
+ static void fini(state_t *s) {
+ XXH32_freeState(*s);
+ }
+
+ static value_t calc(
+ state_t state,
+ size_t len,
+ bufferlist::const_iterator& p
+ ) {
+ XXH32_reset(state, -1);
+ while (len > 0) {
+ const char *data;
+ size_t l = p.get_ptr_and_advance(len, &data);
+ XXH32_update(state, data, l);
+ len -= l;
+ }
+ return XXH32_digest(state);
+ }
+ };
+
+ template<class Alg>
+ int calculate(
+ size_t csum_block_size,
+ size_t offset,
+ size_t length,
+ const bufferlist &bl,
+ vector<char>* csum_data
+ ) {
+ assert(length % csum_block_size == 0);
+ size_t blocks = length / csum_block_size;
+ bufferlist::const_iterator p = bl.begin();
+ assert(bl.length() >= length);
+
+ typename Alg::state_t state;
+ Alg::init(&state);
+
+ assert(csum_data->size() >= (offset + length) / csum_block_size *
+ sizeof(typename Alg::value_t));
+
+ typename Alg::value_t *pv =
+ reinterpret_cast<typename Alg::value_t*>(&(*csum_data)[0]);
+ pv += offset / csum_block_size;
+ while (blocks--) {
+ *pv = Alg::calc(state, csum_block_size, p);
+ ++pv;
+ }
+ Alg::fini(&state);
+ return 0;
+ }
+
+ template<class Alg>
+ int verify(
+ size_t csum_block_size,
+ size_t offset,
+ size_t length,
+ const bufferlist &bl,
+ const vector<char>& csum_data
+ ) {
+ assert(length % csum_block_size == 0);
+ bufferlist::const_iterator p = bl.begin();
+ assert(bl.length() >= length);
+
+ typename Alg::state_t state;
+ Alg::init(&state);
+
+ const typename Alg::value_t *pv =
+ reinterpret_cast<const typename Alg::value_t*>(&csum_data[0]);
+ pv += offset / csum_block_size;
+ size_t pos = offset;
+ while (length > 0) {
+ typename Alg::value_t v = Alg::calc(state, csum_block_size, p);
+ if (*pv != v) {
+ return pos;
+ }
+ ++pv;
+ pos += csum_block_size;
+ length -= csum_block_size;
+ }
+ Alg::fini(&state);
+ return -1; // no errors
+ }
+
+public:
+ int calculate(
+ unsigned type, // bluestore_blob_t::CSumType
+ size_t csum_block_size,
+ size_t offset,
+ size_t length,
+ const bufferlist &bl,
+ vector<char>* csum_data
+ ) {
+ switch (type) {
+ case bluestore_blob_t::CSUM_NONE:
+ return 0;
+ case bluestore_blob_t::CSUM_XXHASH32:
+ return calculate<xxhash32>(csum_block_size, offset, length, bl, csum_data);
+ case bluestore_blob_t::CSUM_CRC32C:
+ return calculate<crc32c>(csum_block_size, offset, length, bl, csum_data);
+ default:
+ return -EOPNOTSUPP;
+ }
+ }
+ int verify(
+ unsigned type, // bluestore_blob_t::CSumType
+ size_t csum_block_size,
+ size_t offset,
+ size_t length,
+ const bufferlist &bl,
+ const vector<char>& csum_data
+ ) {
+ switch (type) {
+ case bluestore_blob_t::CSUM_NONE:
+ return 0;
+ case bluestore_blob_t::CSUM_XXHASH32:
+ return verify<xxhash32>(csum_block_size, offset, length, bl, csum_data);
+ case bluestore_blob_t::CSUM_CRC32C:
+ return verify<crc32c>(csum_block_size, offset, length, bl, csum_data);
+ default:
+ return -EOPNOTSUPP;
+ }
+ }
+
+};
+
+#endif