--- /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"
+
+class Checksummer {
+public:
+ 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>
+ static 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>
+ static 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
+ }
+};
+
+#endif
noinst_HEADERS += \
common/BackTrace.h \
+ common/Checksummer.h \
common/RefCountedObj.h \
common/HeartbeatMap.h \
common/LogClient.h \
#include "bluestore_types.h"
#include "common/Formatter.h"
+#include "common/Checksummer.h"
#include "include/stringify.h"
// bluestore_bdev_label_t
return out;
}
+void bluestore_blob_t::calc_csum(uint64_t b_off, const bufferlist& bl)
+{
+ switch (csum_type) {
+ case CSUM_XXHASH32:
+ Checksummer::calculate<Checksummer::xxhash32>(
+ get_csum_block_size(), b_off, bl.length(), bl, &csum_data);
+ break;
+ case CSUM_CRC32C:
+ Checksummer::calculate<Checksummer::crc32c>(
+ get_csum_block_size(), b_off, bl.length(), bl, &csum_data);
+ break;
+ }
+}
+
+int bluestore_blob_t::verify_csum(uint64_t b_off, const bufferlist& bl) const
+{
+ switch (csum_type) {
+ case CSUM_NONE:
+ return -1;
+ case CSUM_XXHASH32:
+ return Checksummer::verify<Checksummer::xxhash32>(
+ get_csum_block_size(), b_off, bl.length(), bl, csum_data);
+ case CSUM_CRC32C:
+ return Checksummer::verify<Checksummer::crc32c>(
+ get_csum_block_size(), b_off, bl.length(), bl, csum_data);
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
// bluestore_lextent_t
string bluestore_lextent_t::get_flags_string(unsigned flags)
csum_block_order = order;
csum_data.resize(get_csum_value_size() * len / get_csum_block_size());
}
+
+ /// calculate csum for the buffer at the given b_off
+ void calc_csum(uint64_t b_off, const bufferlist& bl);
+
+ /// verify csum: return offset of error, or -1 for no error.
+ int verify_csum(uint64_t b_off, const bufferlist& bl) const;
+
};
WRITE_CLASS_ENCODER(bluestore_blob_t)
ASSERT_FALSE(m.intersects(55, 1));
}
+TEST(bluestore_blob_t, calc_csum)
+{
+ bufferlist bl;
+ bl.append("asdfqwerzxcv");
+ bufferlist bl2;
+ bl2.append("xxxxyyyyzzzz");
+ bluestore_blob_t b;
+ ASSERT_EQ(-1, b.verify_csum(0, bl));
+
+ b.init_csum(bluestore_blob_t::CSUM_CRC32C, 2, 12);
+ b.calc_csum(0, bl);
+ ASSERT_EQ(-1, b.verify_csum(0, bl));
+ ASSERT_EQ(0, b.verify_csum(0, bl2));
+
+ bufferlist f;
+ f.substr_of(bl, 0, 4);
+ ASSERT_EQ(-1, b.verify_csum(0, f));
+ ASSERT_EQ(4, b.verify_csum(4, f));
+ ASSERT_EQ(8, b.verify_csum(8, f));
+
+ bufferlist m;
+ m.substr_of(bl, 4, 4);
+ ASSERT_EQ(0, b.verify_csum(0, m));
+ ASSERT_EQ(-1, b.verify_csum(4, m));
+ ASSERT_EQ(8, b.verify_csum(8, m));
+
+ bufferlist e;
+ e.substr_of(bl, 8, 4);
+ ASSERT_EQ(0, b.verify_csum(0, e));
+ ASSERT_EQ(4, b.verify_csum(4, e));
+ ASSERT_EQ(-1, b.verify_csum(8, e));
+
+ bufferlist n;
+ n.append("xxxx");
+ b.calc_csum(4, n);
+ ASSERT_EQ(-1, b.verify_csum(0, f));
+ ASSERT_EQ(-1, b.verify_csum(4, n));
+ ASSERT_EQ(-1, b.verify_csum(8, e));
+ ASSERT_EQ(4, b.verify_csum(0, bl));
+}
+
TEST(bluestore_onode_t, find_lextent)
{
bluestore_onode_t on;