]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- |
2 | // vim: ts=8 sw=2 smarttab | |
3 | ||
4 | #ifndef CEPH_OS_BLUESTORE_CHECKSUMMER | |
5 | #define CEPH_OS_BLUESTORE_CHECKSUMMER | |
6 | ||
f67539c2 | 7 | #include "include/buffer.h" |
eafe8130 | 8 | #include "include/byteorder.h" |
f67539c2 TL |
9 | #include "include/ceph_assert.h" |
10 | ||
11 | #include "xxHash/xxhash.h" | |
7c673cae FG |
12 | |
13 | class Checksummer { | |
14 | public: | |
15 | enum CSumType { | |
16 | CSUM_NONE = 1, //intentionally set to 1 to be aligned with OSDMnitor's pool_opts_t handling - it treats 0 as unset while we need to distinguish none and unset cases | |
17 | CSUM_XXHASH32 = 2, | |
18 | CSUM_XXHASH64 = 3, | |
19 | CSUM_CRC32C = 4, | |
20 | CSUM_CRC32C_16 = 5, // low 16 bits of crc32c | |
21 | CSUM_CRC32C_8 = 6, // low 8 bits of crc32c | |
22 | CSUM_MAX, | |
23 | }; | |
24 | static const char *get_csum_type_string(unsigned t) { | |
25 | switch (t) { | |
26 | case CSUM_NONE: return "none"; | |
27 | case CSUM_XXHASH32: return "xxhash32"; | |
28 | case CSUM_XXHASH64: return "xxhash64"; | |
29 | case CSUM_CRC32C: return "crc32c"; | |
30 | case CSUM_CRC32C_16: return "crc32c_16"; | |
31 | case CSUM_CRC32C_8: return "crc32c_8"; | |
32 | default: return "???"; | |
33 | } | |
34 | } | |
35 | static int get_csum_string_type(const std::string &s) { | |
36 | if (s == "none") | |
37 | return CSUM_NONE; | |
38 | if (s == "xxhash32") | |
39 | return CSUM_XXHASH32; | |
40 | if (s == "xxhash64") | |
41 | return CSUM_XXHASH64; | |
42 | if (s == "crc32c") | |
43 | return CSUM_CRC32C; | |
44 | if (s == "crc32c_16") | |
45 | return CSUM_CRC32C_16; | |
46 | if (s == "crc32c_8") | |
47 | return CSUM_CRC32C_8; | |
48 | return -EINVAL; | |
49 | } | |
50 | ||
51 | static size_t get_csum_init_value_size(int csum_type) { | |
52 | switch (csum_type) { | |
53 | case CSUM_NONE: return 0; | |
54 | case CSUM_XXHASH32: return sizeof(xxhash32::init_value_t); | |
55 | case CSUM_XXHASH64: return sizeof(xxhash64::init_value_t); | |
56 | case CSUM_CRC32C: return sizeof(crc32c::init_value_t); | |
57 | case CSUM_CRC32C_16: return sizeof(crc32c_16::init_value_t); | |
58 | case CSUM_CRC32C_8: return sizeof(crc32c_8::init_value_t); | |
59 | default: return 0; | |
60 | } | |
61 | } | |
62 | static size_t get_csum_value_size(int csum_type) { | |
63 | switch (csum_type) { | |
64 | case CSUM_NONE: return 0; | |
65 | case CSUM_XXHASH32: return 4; | |
66 | case CSUM_XXHASH64: return 8; | |
67 | case CSUM_CRC32C: return 4; | |
68 | case CSUM_CRC32C_16: return 2; | |
69 | case CSUM_CRC32C_8: return 1; | |
70 | default: return 0; | |
71 | } | |
72 | } | |
73 | ||
74 | struct crc32c { | |
75 | typedef uint32_t init_value_t; | |
eafe8130 | 76 | typedef ceph_le32 value_t; |
7c673cae FG |
77 | |
78 | // we have no execution context/state. | |
79 | typedef int state_t; | |
80 | static void init(state_t *state) { | |
81 | } | |
82 | static void fini(state_t *state) { | |
83 | } | |
84 | ||
eafe8130 | 85 | static init_value_t calc( |
7c673cae FG |
86 | state_t state, |
87 | init_value_t init_value, | |
88 | size_t len, | |
f67539c2 | 89 | ceph::buffer::list::const_iterator& p |
7c673cae FG |
90 | ) { |
91 | return p.crc32c(len, init_value); | |
92 | } | |
93 | }; | |
94 | ||
95 | struct crc32c_16 { | |
96 | typedef uint32_t init_value_t; | |
eafe8130 | 97 | typedef ceph_le16 value_t; |
7c673cae FG |
98 | |
99 | // we have no execution context/state. | |
100 | typedef int state_t; | |
101 | static void init(state_t *state) { | |
102 | } | |
103 | static void fini(state_t *state) { | |
104 | } | |
105 | ||
eafe8130 | 106 | static init_value_t calc( |
7c673cae FG |
107 | state_t state, |
108 | init_value_t init_value, | |
109 | size_t len, | |
f67539c2 | 110 | ceph::buffer::list::const_iterator& p |
7c673cae FG |
111 | ) { |
112 | return p.crc32c(len, init_value) & 0xffff; | |
113 | } | |
114 | }; | |
115 | ||
116 | struct crc32c_8 { | |
117 | typedef uint32_t init_value_t; | |
118 | typedef __u8 value_t; | |
119 | ||
120 | // we have no execution context/state. | |
121 | typedef int state_t; | |
122 | static void init(state_t *state) { | |
123 | } | |
124 | static void fini(state_t *state) { | |
125 | } | |
126 | ||
eafe8130 | 127 | static init_value_t calc( |
7c673cae FG |
128 | state_t state, |
129 | init_value_t init_value, | |
130 | size_t len, | |
f67539c2 | 131 | ceph::buffer::list::const_iterator& p |
7c673cae FG |
132 | ) { |
133 | return p.crc32c(len, init_value) & 0xff; | |
134 | } | |
135 | }; | |
136 | ||
137 | struct xxhash32 { | |
138 | typedef uint32_t init_value_t; | |
eafe8130 | 139 | typedef ceph_le32 value_t; |
7c673cae FG |
140 | |
141 | typedef XXH32_state_t *state_t; | |
142 | static void init(state_t *s) { | |
143 | *s = XXH32_createState(); | |
144 | } | |
145 | static void fini(state_t *s) { | |
146 | XXH32_freeState(*s); | |
147 | } | |
148 | ||
eafe8130 | 149 | static init_value_t calc( |
7c673cae FG |
150 | state_t state, |
151 | init_value_t init_value, | |
152 | size_t len, | |
f67539c2 | 153 | ceph::buffer::list::const_iterator& p |
7c673cae FG |
154 | ) { |
155 | XXH32_reset(state, init_value); | |
156 | while (len > 0) { | |
157 | const char *data; | |
158 | size_t l = p.get_ptr_and_advance(len, &data); | |
159 | XXH32_update(state, data, l); | |
160 | len -= l; | |
161 | } | |
162 | return XXH32_digest(state); | |
163 | } | |
164 | }; | |
165 | ||
166 | struct xxhash64 { | |
167 | typedef uint64_t init_value_t; | |
eafe8130 | 168 | typedef ceph_le64 value_t; |
7c673cae FG |
169 | |
170 | typedef XXH64_state_t *state_t; | |
171 | static void init(state_t *s) { | |
172 | *s = XXH64_createState(); | |
173 | } | |
174 | static void fini(state_t *s) { | |
175 | XXH64_freeState(*s); | |
176 | } | |
177 | ||
eafe8130 | 178 | static init_value_t calc( |
7c673cae FG |
179 | state_t state, |
180 | init_value_t init_value, | |
181 | size_t len, | |
f67539c2 | 182 | ceph::buffer::list::const_iterator& p |
7c673cae FG |
183 | ) { |
184 | XXH64_reset(state, init_value); | |
185 | while (len > 0) { | |
186 | const char *data; | |
187 | size_t l = p.get_ptr_and_advance(len, &data); | |
188 | XXH64_update(state, data, l); | |
189 | len -= l; | |
190 | } | |
191 | return XXH64_digest(state); | |
192 | } | |
193 | }; | |
194 | ||
195 | template<class Alg> | |
196 | static int calculate( | |
197 | size_t csum_block_size, | |
198 | size_t offset, | |
199 | size_t length, | |
f67539c2 TL |
200 | const ceph::buffer::list &bl, |
201 | ceph::buffer::ptr* csum_data | |
7c673cae FG |
202 | ) { |
203 | return calculate<Alg>(-1, csum_block_size, offset, length, bl, csum_data); | |
204 | } | |
205 | ||
206 | template<class Alg> | |
207 | static int calculate( | |
208 | typename Alg::init_value_t init_value, | |
209 | size_t csum_block_size, | |
210 | size_t offset, | |
211 | size_t length, | |
f67539c2 TL |
212 | const ceph::buffer::list &bl, |
213 | ceph::buffer::ptr* csum_data) { | |
11fdf7f2 | 214 | ceph_assert(length % csum_block_size == 0); |
7c673cae | 215 | size_t blocks = length / csum_block_size; |
f67539c2 | 216 | ceph::buffer::list::const_iterator p = bl.begin(); |
11fdf7f2 | 217 | ceph_assert(bl.length() >= length); |
7c673cae FG |
218 | |
219 | typename Alg::state_t state; | |
220 | Alg::init(&state); | |
221 | ||
11fdf7f2 | 222 | ceph_assert(csum_data->length() >= (offset + length) / csum_block_size * |
7c673cae FG |
223 | sizeof(typename Alg::value_t)); |
224 | ||
225 | typename Alg::value_t *pv = | |
226 | reinterpret_cast<typename Alg::value_t*>(csum_data->c_str()); | |
227 | pv += offset / csum_block_size; | |
228 | while (blocks--) { | |
229 | *pv = Alg::calc(state, init_value, csum_block_size, p); | |
230 | ++pv; | |
231 | } | |
232 | Alg::fini(&state); | |
233 | return 0; | |
234 | } | |
235 | ||
236 | template<class Alg> | |
237 | static int verify( | |
238 | size_t csum_block_size, | |
239 | size_t offset, | |
240 | size_t length, | |
f67539c2 TL |
241 | const ceph::buffer::list &bl, |
242 | const ceph::buffer::ptr& csum_data, | |
7c673cae FG |
243 | uint64_t *bad_csum=0 |
244 | ) { | |
11fdf7f2 | 245 | ceph_assert(length % csum_block_size == 0); |
f67539c2 | 246 | ceph::buffer::list::const_iterator p = bl.begin(); |
11fdf7f2 | 247 | ceph_assert(bl.length() >= length); |
7c673cae FG |
248 | |
249 | typename Alg::state_t state; | |
250 | Alg::init(&state); | |
251 | ||
252 | const typename Alg::value_t *pv = | |
253 | reinterpret_cast<const typename Alg::value_t*>(csum_data.c_str()); | |
254 | pv += offset / csum_block_size; | |
255 | size_t pos = offset; | |
256 | while (length > 0) { | |
eafe8130 | 257 | typename Alg::init_value_t v = Alg::calc(state, -1, csum_block_size, p); |
7c673cae FG |
258 | if (*pv != v) { |
259 | if (bad_csum) { | |
260 | *bad_csum = v; | |
261 | } | |
262 | Alg::fini(&state); | |
263 | return pos; | |
264 | } | |
265 | ++pv; | |
266 | pos += csum_block_size; | |
267 | length -= csum_block_size; | |
268 | } | |
269 | Alg::fini(&state); | |
270 | return -1; // no errors | |
271 | } | |
272 | }; | |
273 | ||
274 | #endif |