]>
Commit | Line | Data |
---|---|---|
a739ff3f ST |
1 | /* |
2 | * Copyright (C) 2015 Google, Inc. | |
3 | * | |
4 | * Author: Sami Tolvanen <[email protected]> | |
5 | * | |
6 | * This program is free software; you can redistribute it and/or modify it | |
7 | * under the terms of the GNU General Public License as published by the Free | |
8 | * Software Foundation; either version 2 of the License, or (at your option) | |
9 | * any later version. | |
10 | */ | |
11 | ||
12 | #include "dm-verity-fec.h" | |
13 | #include <linux/math64.h> | |
14 | ||
15 | #define DM_MSG_PREFIX "verity-fec" | |
16 | ||
17 | /* | |
18 | * If error correction has been configured, returns true. | |
19 | */ | |
20 | bool verity_fec_is_enabled(struct dm_verity *v) | |
21 | { | |
22 | return v->fec && v->fec->dev; | |
23 | } | |
24 | ||
25 | /* | |
26 | * Return a pointer to dm_verity_fec_io after dm_verity_io and its variable | |
27 | * length fields. | |
28 | */ | |
29 | static inline struct dm_verity_fec_io *fec_io(struct dm_verity_io *io) | |
30 | { | |
31 | return (struct dm_verity_fec_io *) verity_io_digest_end(io->v, io); | |
32 | } | |
33 | ||
34 | /* | |
35 | * Return an interleaved offset for a byte in RS block. | |
36 | */ | |
37 | static inline u64 fec_interleave(struct dm_verity *v, u64 offset) | |
38 | { | |
39 | u32 mod; | |
40 | ||
41 | mod = do_div(offset, v->fec->rsn); | |
42 | return offset + mod * (v->fec->rounds << v->data_dev_block_bits); | |
43 | } | |
44 | ||
45 | /* | |
46 | * Decode an RS block using Reed-Solomon. | |
47 | */ | |
48 | static int fec_decode_rs8(struct dm_verity *v, struct dm_verity_fec_io *fio, | |
49 | u8 *data, u8 *fec, int neras) | |
50 | { | |
51 | int i; | |
52 | uint16_t par[DM_VERITY_FEC_RSM - DM_VERITY_FEC_MIN_RSN]; | |
53 | ||
54 | for (i = 0; i < v->fec->roots; i++) | |
55 | par[i] = fec[i]; | |
56 | ||
57 | return decode_rs8(fio->rs, data, par, v->fec->rsn, NULL, neras, | |
58 | fio->erasures, 0, NULL); | |
59 | } | |
60 | ||
61 | /* | |
62 | * Read error-correcting codes for the requested RS block. Returns a pointer | |
63 | * to the data block. Caller is responsible for releasing buf. | |
64 | */ | |
65 | static u8 *fec_read_parity(struct dm_verity *v, u64 rsb, int index, | |
66 | unsigned *offset, struct dm_buffer **buf) | |
67 | { | |
68 | u64 position, block; | |
69 | u8 *res; | |
70 | ||
71 | position = (index + rsb) * v->fec->roots; | |
72 | block = position >> v->data_dev_block_bits; | |
73 | *offset = (unsigned)(position - (block << v->data_dev_block_bits)); | |
74 | ||
75 | res = dm_bufio_read(v->fec->bufio, v->fec->start + block, buf); | |
76 | if (unlikely(IS_ERR(res))) { | |
77 | DMERR("%s: FEC %llu: parity read failed (block %llu): %ld", | |
78 | v->data_dev->name, (unsigned long long)rsb, | |
79 | (unsigned long long)(v->fec->start + block), | |
80 | PTR_ERR(res)); | |
81 | *buf = NULL; | |
82 | } | |
83 | ||
84 | return res; | |
85 | } | |
86 | ||
87 | /* Loop over each preallocated buffer slot. */ | |
88 | #define fec_for_each_prealloc_buffer(__i) \ | |
89 | for (__i = 0; __i < DM_VERITY_FEC_BUF_PREALLOC; __i++) | |
90 | ||
91 | /* Loop over each extra buffer slot. */ | |
92 | #define fec_for_each_extra_buffer(io, __i) \ | |
93 | for (__i = DM_VERITY_FEC_BUF_PREALLOC; __i < DM_VERITY_FEC_BUF_MAX; __i++) | |
94 | ||
95 | /* Loop over each allocated buffer. */ | |
96 | #define fec_for_each_buffer(io, __i) \ | |
97 | for (__i = 0; __i < (io)->nbufs; __i++) | |
98 | ||
99 | /* Loop over each RS block in each allocated buffer. */ | |
100 | #define fec_for_each_buffer_rs_block(io, __i, __j) \ | |
101 | fec_for_each_buffer(io, __i) \ | |
102 | for (__j = 0; __j < 1 << DM_VERITY_FEC_BUF_RS_BITS; __j++) | |
103 | ||
104 | /* | |
105 | * Return a pointer to the current RS block when called inside | |
106 | * fec_for_each_buffer_rs_block. | |
107 | */ | |
108 | static inline u8 *fec_buffer_rs_block(struct dm_verity *v, | |
109 | struct dm_verity_fec_io *fio, | |
110 | unsigned i, unsigned j) | |
111 | { | |
112 | return &fio->bufs[i][j * v->fec->rsn]; | |
113 | } | |
114 | ||
115 | /* | |
116 | * Return an index to the current RS block when called inside | |
117 | * fec_for_each_buffer_rs_block. | |
118 | */ | |
119 | static inline unsigned fec_buffer_rs_index(unsigned i, unsigned j) | |
120 | { | |
121 | return (i << DM_VERITY_FEC_BUF_RS_BITS) + j; | |
122 | } | |
123 | ||
124 | /* | |
125 | * Decode all RS blocks from buffers and copy corrected bytes into fio->output | |
126 | * starting from block_offset. | |
127 | */ | |
128 | static int fec_decode_bufs(struct dm_verity *v, struct dm_verity_fec_io *fio, | |
129 | u64 rsb, int byte_index, unsigned block_offset, | |
130 | int neras) | |
131 | { | |
132 | int r, corrected = 0, res; | |
133 | struct dm_buffer *buf; | |
134 | unsigned n, i, offset; | |
135 | u8 *par, *block; | |
136 | ||
137 | par = fec_read_parity(v, rsb, block_offset, &offset, &buf); | |
138 | if (IS_ERR(par)) | |
139 | return PTR_ERR(par); | |
140 | ||
141 | /* | |
142 | * Decode the RS blocks we have in bufs. Each RS block results in | |
143 | * one corrected target byte and consumes fec->roots parity bytes. | |
144 | */ | |
145 | fec_for_each_buffer_rs_block(fio, n, i) { | |
146 | block = fec_buffer_rs_block(v, fio, n, i); | |
147 | res = fec_decode_rs8(v, fio, block, &par[offset], neras); | |
148 | if (res < 0) { | |
a739ff3f ST |
149 | r = res; |
150 | goto error; | |
151 | } | |
152 | ||
153 | corrected += res; | |
154 | fio->output[block_offset] = block[byte_index]; | |
155 | ||
156 | block_offset++; | |
157 | if (block_offset >= 1 << v->data_dev_block_bits) | |
158 | goto done; | |
159 | ||
160 | /* read the next block when we run out of parity bytes */ | |
161 | offset += v->fec->roots; | |
162 | if (offset >= 1 << v->data_dev_block_bits) { | |
163 | dm_bufio_release(buf); | |
164 | ||
165 | par = fec_read_parity(v, rsb, block_offset, &offset, &buf); | |
166 | if (unlikely(IS_ERR(par))) | |
167 | return PTR_ERR(par); | |
168 | } | |
169 | } | |
170 | done: | |
171 | r = corrected; | |
172 | error: | |
86e3e83b ST |
173 | dm_bufio_release(buf); |
174 | ||
a739ff3f ST |
175 | if (r < 0 && neras) |
176 | DMERR_LIMIT("%s: FEC %llu: failed to correct: %d", | |
177 | v->data_dev->name, (unsigned long long)rsb, r); | |
178 | else if (r > 0) | |
179 | DMWARN_LIMIT("%s: FEC %llu: corrected %d errors", | |
180 | v->data_dev->name, (unsigned long long)rsb, r); | |
181 | ||
182 | return r; | |
183 | } | |
184 | ||
185 | /* | |
186 | * Locate data block erasures using verity hashes. | |
187 | */ | |
188 | static int fec_is_erasure(struct dm_verity *v, struct dm_verity_io *io, | |
189 | u8 *want_digest, u8 *data) | |
190 | { | |
d1ac3ff0 | 191 | if (unlikely(verity_hash(v, verity_io_hash_req(v, io), |
a739ff3f ST |
192 | data, 1 << v->data_dev_block_bits, |
193 | verity_io_real_digest(v, io)))) | |
194 | return 0; | |
195 | ||
196 | return memcmp(verity_io_real_digest(v, io), want_digest, | |
197 | v->digest_size) != 0; | |
198 | } | |
199 | ||
200 | /* | |
201 | * Read data blocks that are part of the RS block and deinterleave as much as | |
202 | * fits into buffers. Check for erasure locations if @neras is non-NULL. | |
203 | */ | |
204 | static int fec_read_bufs(struct dm_verity *v, struct dm_verity_io *io, | |
205 | u64 rsb, u64 target, unsigned block_offset, | |
206 | int *neras) | |
207 | { | |
0cc37c2d | 208 | bool is_zero; |
a739ff3f ST |
209 | int i, j, target_index = -1; |
210 | struct dm_buffer *buf; | |
211 | struct dm_bufio_client *bufio; | |
212 | struct dm_verity_fec_io *fio = fec_io(io); | |
213 | u64 block, ileaved; | |
214 | u8 *bbuf, *rs_block; | |
215 | u8 want_digest[v->digest_size]; | |
216 | unsigned n, k; | |
217 | ||
218 | if (neras) | |
219 | *neras = 0; | |
220 | ||
221 | /* | |
222 | * read each of the rsn data blocks that are part of the RS block, and | |
223 | * interleave contents to available bufs | |
224 | */ | |
225 | for (i = 0; i < v->fec->rsn; i++) { | |
226 | ileaved = fec_interleave(v, rsb * v->fec->rsn + i); | |
227 | ||
228 | /* | |
229 | * target is the data block we want to correct, target_index is | |
230 | * the index of this block within the rsn RS blocks | |
231 | */ | |
232 | if (ileaved == target) | |
233 | target_index = i; | |
234 | ||
235 | block = ileaved >> v->data_dev_block_bits; | |
236 | bufio = v->fec->data_bufio; | |
237 | ||
238 | if (block >= v->data_blocks) { | |
239 | block -= v->data_blocks; | |
240 | ||
241 | /* | |
242 | * blocks outside the area were assumed to contain | |
243 | * zeros when encoding data was generated | |
244 | */ | |
245 | if (unlikely(block >= v->fec->hash_blocks)) | |
246 | continue; | |
247 | ||
248 | block += v->hash_start; | |
249 | bufio = v->bufio; | |
250 | } | |
251 | ||
252 | bbuf = dm_bufio_read(bufio, block, &buf); | |
253 | if (unlikely(IS_ERR(bbuf))) { | |
254 | DMWARN_LIMIT("%s: FEC %llu: read failed (%llu): %ld", | |
255 | v->data_dev->name, | |
256 | (unsigned long long)rsb, | |
257 | (unsigned long long)block, PTR_ERR(bbuf)); | |
258 | ||
259 | /* assume the block is corrupted */ | |
260 | if (neras && *neras <= v->fec->roots) | |
261 | fio->erasures[(*neras)++] = i; | |
262 | ||
263 | continue; | |
264 | } | |
265 | ||
266 | /* locate erasures if the block is on the data device */ | |
267 | if (bufio == v->fec->data_bufio && | |
0cc37c2d ST |
268 | verity_hash_for_block(v, io, block, want_digest, |
269 | &is_zero) == 0) { | |
270 | /* skip known zero blocks entirely */ | |
271 | if (is_zero) | |
86e3e83b | 272 | goto done; |
0cc37c2d | 273 | |
a739ff3f ST |
274 | /* |
275 | * skip if we have already found the theoretical | |
276 | * maximum number (i.e. fec->roots) of erasures | |
277 | */ | |
278 | if (neras && *neras <= v->fec->roots && | |
279 | fec_is_erasure(v, io, want_digest, bbuf)) | |
280 | fio->erasures[(*neras)++] = i; | |
281 | } | |
282 | ||
283 | /* | |
284 | * deinterleave and copy the bytes that fit into bufs, | |
285 | * starting from block_offset | |
286 | */ | |
287 | fec_for_each_buffer_rs_block(fio, n, j) { | |
288 | k = fec_buffer_rs_index(n, j) + block_offset; | |
289 | ||
290 | if (k >= 1 << v->data_dev_block_bits) | |
291 | goto done; | |
292 | ||
293 | rs_block = fec_buffer_rs_block(v, fio, n, j); | |
294 | rs_block[i] = bbuf[k]; | |
295 | } | |
296 | done: | |
297 | dm_bufio_release(buf); | |
298 | } | |
299 | ||
300 | return target_index; | |
301 | } | |
302 | ||
303 | /* | |
304 | * Allocate RS control structure and FEC buffers from preallocated mempools, | |
305 | * and attempt to allocate as many extra buffers as available. | |
306 | */ | |
307 | static int fec_alloc_bufs(struct dm_verity *v, struct dm_verity_fec_io *fio) | |
308 | { | |
309 | unsigned n; | |
310 | ||
34c96507 N |
311 | if (!fio->rs) |
312 | fio->rs = mempool_alloc(v->fec->rs_pool, GFP_NOIO); | |
a739ff3f ST |
313 | |
314 | fec_for_each_prealloc_buffer(n) { | |
315 | if (fio->bufs[n]) | |
316 | continue; | |
317 | ||
34c96507 | 318 | fio->bufs[n] = mempool_alloc(v->fec->prealloc_pool, GFP_NOWAIT); |
a739ff3f ST |
319 | if (unlikely(!fio->bufs[n])) { |
320 | DMERR("failed to allocate FEC buffer"); | |
321 | return -ENOMEM; | |
322 | } | |
323 | } | |
324 | ||
325 | /* try to allocate the maximum number of buffers */ | |
326 | fec_for_each_extra_buffer(fio, n) { | |
327 | if (fio->bufs[n]) | |
328 | continue; | |
329 | ||
34c96507 | 330 | fio->bufs[n] = mempool_alloc(v->fec->extra_pool, GFP_NOWAIT); |
a739ff3f ST |
331 | /* we can manage with even one buffer if necessary */ |
332 | if (unlikely(!fio->bufs[n])) | |
333 | break; | |
334 | } | |
335 | fio->nbufs = n; | |
336 | ||
34c96507 | 337 | if (!fio->output) |
a739ff3f ST |
338 | fio->output = mempool_alloc(v->fec->output_pool, GFP_NOIO); |
339 | ||
a739ff3f ST |
340 | return 0; |
341 | } | |
342 | ||
343 | /* | |
344 | * Initialize buffers and clear erasures. fec_read_bufs() assumes buffers are | |
345 | * zeroed before deinterleaving. | |
346 | */ | |
347 | static void fec_init_bufs(struct dm_verity *v, struct dm_verity_fec_io *fio) | |
348 | { | |
349 | unsigned n; | |
350 | ||
351 | fec_for_each_buffer(fio, n) | |
352 | memset(fio->bufs[n], 0, v->fec->rsn << DM_VERITY_FEC_BUF_RS_BITS); | |
353 | ||
354 | memset(fio->erasures, 0, sizeof(fio->erasures)); | |
355 | } | |
356 | ||
357 | /* | |
358 | * Decode all RS blocks in a single data block and return the target block | |
359 | * (indicated by @offset) in fio->output. If @use_erasures is non-zero, uses | |
360 | * hashes to locate erasures. | |
361 | */ | |
362 | static int fec_decode_rsb(struct dm_verity *v, struct dm_verity_io *io, | |
363 | struct dm_verity_fec_io *fio, u64 rsb, u64 offset, | |
364 | bool use_erasures) | |
365 | { | |
366 | int r, neras = 0; | |
367 | unsigned pos; | |
368 | ||
369 | r = fec_alloc_bufs(v, fio); | |
370 | if (unlikely(r < 0)) | |
371 | return r; | |
372 | ||
373 | for (pos = 0; pos < 1 << v->data_dev_block_bits; ) { | |
374 | fec_init_bufs(v, fio); | |
375 | ||
376 | r = fec_read_bufs(v, io, rsb, offset, pos, | |
377 | use_erasures ? &neras : NULL); | |
378 | if (unlikely(r < 0)) | |
379 | return r; | |
380 | ||
381 | r = fec_decode_bufs(v, fio, rsb, r, pos, neras); | |
382 | if (r < 0) | |
383 | return r; | |
384 | ||
385 | pos += fio->nbufs << DM_VERITY_FEC_BUF_RS_BITS; | |
386 | } | |
387 | ||
388 | /* Always re-validate the corrected block against the expected hash */ | |
d1ac3ff0 | 389 | r = verity_hash(v, verity_io_hash_req(v, io), fio->output, |
a739ff3f ST |
390 | 1 << v->data_dev_block_bits, |
391 | verity_io_real_digest(v, io)); | |
392 | if (unlikely(r < 0)) | |
393 | return r; | |
394 | ||
395 | if (memcmp(verity_io_real_digest(v, io), verity_io_want_digest(v, io), | |
396 | v->digest_size)) { | |
397 | DMERR_LIMIT("%s: FEC %llu: failed to correct (%d erasures)", | |
398 | v->data_dev->name, (unsigned long long)rsb, neras); | |
399 | return -EILSEQ; | |
400 | } | |
401 | ||
402 | return 0; | |
403 | } | |
404 | ||
405 | static int fec_bv_copy(struct dm_verity *v, struct dm_verity_io *io, u8 *data, | |
406 | size_t len) | |
407 | { | |
408 | struct dm_verity_fec_io *fio = fec_io(io); | |
409 | ||
410 | memcpy(data, &fio->output[fio->output_pos], len); | |
411 | fio->output_pos += len; | |
412 | ||
413 | return 0; | |
414 | } | |
415 | ||
416 | /* | |
417 | * Correct errors in a block. Copies corrected block to dest if non-NULL, | |
418 | * otherwise to a bio_vec starting from iter. | |
419 | */ | |
420 | int verity_fec_decode(struct dm_verity *v, struct dm_verity_io *io, | |
421 | enum verity_block_type type, sector_t block, u8 *dest, | |
422 | struct bvec_iter *iter) | |
423 | { | |
424 | int r; | |
425 | struct dm_verity_fec_io *fio = fec_io(io); | |
426 | u64 offset, res, rsb; | |
427 | ||
428 | if (!verity_fec_is_enabled(v)) | |
429 | return -EOPNOTSUPP; | |
430 | ||
f1a880a9 ST |
431 | if (fio->level >= DM_VERITY_FEC_MAX_RECURSION) { |
432 | DMWARN_LIMIT("%s: FEC: recursion too deep", v->data_dev->name); | |
433 | return -EIO; | |
434 | } | |
435 | ||
436 | fio->level++; | |
437 | ||
a739ff3f ST |
438 | if (type == DM_VERITY_BLOCK_TYPE_METADATA) |
439 | block += v->data_blocks; | |
440 | ||
441 | /* | |
442 | * For RS(M, N), the continuous FEC data is divided into blocks of N | |
443 | * bytes. Since block size may not be divisible by N, the last block | |
444 | * is zero padded when decoding. | |
445 | * | |
446 | * Each byte of the block is covered by a different RS(M, N) code, | |
447 | * and each code is interleaved over N blocks to make it less likely | |
448 | * that bursty corruption will leave us in unrecoverable state. | |
449 | */ | |
450 | ||
451 | offset = block << v->data_dev_block_bits; | |
602d1657 | 452 | res = div64_u64(offset, v->fec->rounds << v->data_dev_block_bits); |
a739ff3f ST |
453 | |
454 | /* | |
455 | * The base RS block we can feed to the interleaver to find out all | |
456 | * blocks required for decoding. | |
457 | */ | |
458 | rsb = offset - res * (v->fec->rounds << v->data_dev_block_bits); | |
459 | ||
460 | /* | |
461 | * Locating erasures is slow, so attempt to recover the block without | |
462 | * them first. Do a second attempt with erasures if the corruption is | |
463 | * bad enough. | |
464 | */ | |
465 | r = fec_decode_rsb(v, io, fio, rsb, offset, false); | |
466 | if (r < 0) { | |
467 | r = fec_decode_rsb(v, io, fio, rsb, offset, true); | |
468 | if (r < 0) | |
f1a880a9 | 469 | goto done; |
a739ff3f ST |
470 | } |
471 | ||
472 | if (dest) | |
473 | memcpy(dest, fio->output, 1 << v->data_dev_block_bits); | |
474 | else if (iter) { | |
475 | fio->output_pos = 0; | |
476 | r = verity_for_bv_block(v, io, iter, fec_bv_copy); | |
477 | } | |
478 | ||
f1a880a9 ST |
479 | done: |
480 | fio->level--; | |
a739ff3f ST |
481 | return r; |
482 | } | |
483 | ||
484 | /* | |
485 | * Clean up per-bio data. | |
486 | */ | |
487 | void verity_fec_finish_io(struct dm_verity_io *io) | |
488 | { | |
489 | unsigned n; | |
490 | struct dm_verity_fec *f = io->v->fec; | |
491 | struct dm_verity_fec_io *fio = fec_io(io); | |
492 | ||
493 | if (!verity_fec_is_enabled(io->v)) | |
494 | return; | |
495 | ||
496 | mempool_free(fio->rs, f->rs_pool); | |
497 | ||
498 | fec_for_each_prealloc_buffer(n) | |
499 | mempool_free(fio->bufs[n], f->prealloc_pool); | |
500 | ||
501 | fec_for_each_extra_buffer(fio, n) | |
502 | mempool_free(fio->bufs[n], f->extra_pool); | |
503 | ||
504 | mempool_free(fio->output, f->output_pool); | |
505 | } | |
506 | ||
507 | /* | |
508 | * Initialize per-bio data. | |
509 | */ | |
510 | void verity_fec_init_io(struct dm_verity_io *io) | |
511 | { | |
512 | struct dm_verity_fec_io *fio = fec_io(io); | |
513 | ||
514 | if (!verity_fec_is_enabled(io->v)) | |
515 | return; | |
516 | ||
517 | fio->rs = NULL; | |
518 | memset(fio->bufs, 0, sizeof(fio->bufs)); | |
519 | fio->nbufs = 0; | |
520 | fio->output = NULL; | |
f1a880a9 | 521 | fio->level = 0; |
a739ff3f ST |
522 | } |
523 | ||
524 | /* | |
525 | * Append feature arguments and values to the status table. | |
526 | */ | |
527 | unsigned verity_fec_status_table(struct dm_verity *v, unsigned sz, | |
528 | char *result, unsigned maxlen) | |
529 | { | |
530 | if (!verity_fec_is_enabled(v)) | |
531 | return sz; | |
532 | ||
533 | DMEMIT(" " DM_VERITY_OPT_FEC_DEV " %s " | |
534 | DM_VERITY_OPT_FEC_BLOCKS " %llu " | |
535 | DM_VERITY_OPT_FEC_START " %llu " | |
536 | DM_VERITY_OPT_FEC_ROOTS " %d", | |
537 | v->fec->dev->name, | |
538 | (unsigned long long)v->fec->blocks, | |
539 | (unsigned long long)v->fec->start, | |
540 | v->fec->roots); | |
541 | ||
542 | return sz; | |
543 | } | |
544 | ||
545 | void verity_fec_dtr(struct dm_verity *v) | |
546 | { | |
547 | struct dm_verity_fec *f = v->fec; | |
548 | ||
549 | if (!verity_fec_is_enabled(v)) | |
550 | goto out; | |
551 | ||
552 | mempool_destroy(f->rs_pool); | |
553 | mempool_destroy(f->prealloc_pool); | |
554 | mempool_destroy(f->extra_pool); | |
555 | kmem_cache_destroy(f->cache); | |
556 | ||
557 | if (f->data_bufio) | |
558 | dm_bufio_client_destroy(f->data_bufio); | |
559 | if (f->bufio) | |
560 | dm_bufio_client_destroy(f->bufio); | |
561 | ||
562 | if (f->dev) | |
563 | dm_put_device(v->ti, f->dev); | |
564 | out: | |
565 | kfree(f); | |
566 | v->fec = NULL; | |
567 | } | |
568 | ||
569 | static void *fec_rs_alloc(gfp_t gfp_mask, void *pool_data) | |
570 | { | |
571 | struct dm_verity *v = (struct dm_verity *)pool_data; | |
572 | ||
573 | return init_rs(8, 0x11d, 0, 1, v->fec->roots); | |
574 | } | |
575 | ||
576 | static void fec_rs_free(void *element, void *pool_data) | |
577 | { | |
578 | struct rs_control *rs = (struct rs_control *)element; | |
579 | ||
580 | if (rs) | |
581 | free_rs(rs); | |
582 | } | |
583 | ||
584 | bool verity_is_fec_opt_arg(const char *arg_name) | |
585 | { | |
586 | return (!strcasecmp(arg_name, DM_VERITY_OPT_FEC_DEV) || | |
587 | !strcasecmp(arg_name, DM_VERITY_OPT_FEC_BLOCKS) || | |
588 | !strcasecmp(arg_name, DM_VERITY_OPT_FEC_START) || | |
589 | !strcasecmp(arg_name, DM_VERITY_OPT_FEC_ROOTS)); | |
590 | } | |
591 | ||
592 | int verity_fec_parse_opt_args(struct dm_arg_set *as, struct dm_verity *v, | |
593 | unsigned *argc, const char *arg_name) | |
594 | { | |
595 | int r; | |
596 | struct dm_target *ti = v->ti; | |
597 | const char *arg_value; | |
598 | unsigned long long num_ll; | |
599 | unsigned char num_c; | |
600 | char dummy; | |
601 | ||
602 | if (!*argc) { | |
603 | ti->error = "FEC feature arguments require a value"; | |
604 | return -EINVAL; | |
605 | } | |
606 | ||
607 | arg_value = dm_shift_arg(as); | |
608 | (*argc)--; | |
609 | ||
610 | if (!strcasecmp(arg_name, DM_VERITY_OPT_FEC_DEV)) { | |
611 | r = dm_get_device(ti, arg_value, FMODE_READ, &v->fec->dev); | |
612 | if (r) { | |
613 | ti->error = "FEC device lookup failed"; | |
614 | return r; | |
615 | } | |
616 | ||
617 | } else if (!strcasecmp(arg_name, DM_VERITY_OPT_FEC_BLOCKS)) { | |
618 | if (sscanf(arg_value, "%llu%c", &num_ll, &dummy) != 1 || | |
619 | ((sector_t)(num_ll << (v->data_dev_block_bits - SECTOR_SHIFT)) | |
620 | >> (v->data_dev_block_bits - SECTOR_SHIFT) != num_ll)) { | |
621 | ti->error = "Invalid " DM_VERITY_OPT_FEC_BLOCKS; | |
622 | return -EINVAL; | |
623 | } | |
624 | v->fec->blocks = num_ll; | |
625 | ||
626 | } else if (!strcasecmp(arg_name, DM_VERITY_OPT_FEC_START)) { | |
627 | if (sscanf(arg_value, "%llu%c", &num_ll, &dummy) != 1 || | |
628 | ((sector_t)(num_ll << (v->data_dev_block_bits - SECTOR_SHIFT)) >> | |
629 | (v->data_dev_block_bits - SECTOR_SHIFT) != num_ll)) { | |
630 | ti->error = "Invalid " DM_VERITY_OPT_FEC_START; | |
631 | return -EINVAL; | |
632 | } | |
633 | v->fec->start = num_ll; | |
634 | ||
635 | } else if (!strcasecmp(arg_name, DM_VERITY_OPT_FEC_ROOTS)) { | |
636 | if (sscanf(arg_value, "%hhu%c", &num_c, &dummy) != 1 || !num_c || | |
637 | num_c < (DM_VERITY_FEC_RSM - DM_VERITY_FEC_MAX_RSN) || | |
638 | num_c > (DM_VERITY_FEC_RSM - DM_VERITY_FEC_MIN_RSN)) { | |
639 | ti->error = "Invalid " DM_VERITY_OPT_FEC_ROOTS; | |
640 | return -EINVAL; | |
641 | } | |
642 | v->fec->roots = num_c; | |
643 | ||
644 | } else { | |
645 | ti->error = "Unrecognized verity FEC feature request"; | |
646 | return -EINVAL; | |
647 | } | |
648 | ||
649 | return 0; | |
650 | } | |
651 | ||
652 | /* | |
653 | * Allocate dm_verity_fec for v->fec. Must be called before verity_fec_ctr. | |
654 | */ | |
655 | int verity_fec_ctr_alloc(struct dm_verity *v) | |
656 | { | |
657 | struct dm_verity_fec *f; | |
658 | ||
659 | f = kzalloc(sizeof(struct dm_verity_fec), GFP_KERNEL); | |
660 | if (!f) { | |
661 | v->ti->error = "Cannot allocate FEC structure"; | |
662 | return -ENOMEM; | |
663 | } | |
664 | v->fec = f; | |
665 | ||
666 | return 0; | |
667 | } | |
668 | ||
669 | /* | |
670 | * Validate arguments and preallocate memory. Must be called after arguments | |
671 | * have been parsed using verity_fec_parse_opt_args. | |
672 | */ | |
673 | int verity_fec_ctr(struct dm_verity *v) | |
674 | { | |
675 | struct dm_verity_fec *f = v->fec; | |
676 | struct dm_target *ti = v->ti; | |
677 | u64 hash_blocks; | |
678 | ||
679 | if (!verity_fec_is_enabled(v)) { | |
680 | verity_fec_dtr(v); | |
681 | return 0; | |
682 | } | |
683 | ||
684 | /* | |
685 | * FEC is computed over data blocks, possible metadata, and | |
686 | * hash blocks. In other words, FEC covers total of fec_blocks | |
687 | * blocks consisting of the following: | |
688 | * | |
689 | * data blocks | hash blocks | metadata (optional) | |
690 | * | |
691 | * We allow metadata after hash blocks to support a use case | |
692 | * where all data is stored on the same device and FEC covers | |
693 | * the entire area. | |
694 | * | |
695 | * If metadata is included, we require it to be available on the | |
696 | * hash device after the hash blocks. | |
697 | */ | |
698 | ||
699 | hash_blocks = v->hash_blocks - v->hash_start; | |
700 | ||
701 | /* | |
702 | * Require matching block sizes for data and hash devices for | |
703 | * simplicity. | |
704 | */ | |
705 | if (v->data_dev_block_bits != v->hash_dev_block_bits) { | |
706 | ti->error = "Block sizes must match to use FEC"; | |
707 | return -EINVAL; | |
708 | } | |
709 | ||
710 | if (!f->roots) { | |
711 | ti->error = "Missing " DM_VERITY_OPT_FEC_ROOTS; | |
712 | return -EINVAL; | |
713 | } | |
714 | f->rsn = DM_VERITY_FEC_RSM - f->roots; | |
715 | ||
716 | if (!f->blocks) { | |
717 | ti->error = "Missing " DM_VERITY_OPT_FEC_BLOCKS; | |
718 | return -EINVAL; | |
719 | } | |
720 | ||
721 | f->rounds = f->blocks; | |
722 | if (sector_div(f->rounds, f->rsn)) | |
723 | f->rounds++; | |
724 | ||
725 | /* | |
726 | * Due to optional metadata, f->blocks can be larger than | |
727 | * data_blocks and hash_blocks combined. | |
728 | */ | |
729 | if (f->blocks < v->data_blocks + hash_blocks || !f->rounds) { | |
730 | ti->error = "Invalid " DM_VERITY_OPT_FEC_BLOCKS; | |
731 | return -EINVAL; | |
732 | } | |
733 | ||
734 | /* | |
735 | * Metadata is accessed through the hash device, so we require | |
736 | * it to be large enough. | |
737 | */ | |
738 | f->hash_blocks = f->blocks - v->data_blocks; | |
739 | if (dm_bufio_get_device_size(v->bufio) < f->hash_blocks) { | |
740 | ti->error = "Hash device is too small for " | |
741 | DM_VERITY_OPT_FEC_BLOCKS; | |
742 | return -E2BIG; | |
743 | } | |
744 | ||
745 | f->bufio = dm_bufio_client_create(f->dev->bdev, | |
746 | 1 << v->data_dev_block_bits, | |
747 | 1, 0, NULL, NULL); | |
748 | if (IS_ERR(f->bufio)) { | |
749 | ti->error = "Cannot initialize FEC bufio client"; | |
750 | return PTR_ERR(f->bufio); | |
751 | } | |
752 | ||
753 | if (dm_bufio_get_device_size(f->bufio) < | |
754 | ((f->start + f->rounds * f->roots) >> v->data_dev_block_bits)) { | |
755 | ti->error = "FEC device is too small"; | |
756 | return -E2BIG; | |
757 | } | |
758 | ||
759 | f->data_bufio = dm_bufio_client_create(v->data_dev->bdev, | |
760 | 1 << v->data_dev_block_bits, | |
761 | 1, 0, NULL, NULL); | |
762 | if (IS_ERR(f->data_bufio)) { | |
763 | ti->error = "Cannot initialize FEC data bufio client"; | |
764 | return PTR_ERR(f->data_bufio); | |
765 | } | |
766 | ||
767 | if (dm_bufio_get_device_size(f->data_bufio) < v->data_blocks) { | |
768 | ti->error = "Data device is too small"; | |
769 | return -E2BIG; | |
770 | } | |
771 | ||
772 | /* Preallocate an rs_control structure for each worker thread */ | |
773 | f->rs_pool = mempool_create(num_online_cpus(), fec_rs_alloc, | |
774 | fec_rs_free, (void *) v); | |
775 | if (!f->rs_pool) { | |
776 | ti->error = "Cannot allocate RS pool"; | |
777 | return -ENOMEM; | |
778 | } | |
779 | ||
780 | f->cache = kmem_cache_create("dm_verity_fec_buffers", | |
781 | f->rsn << DM_VERITY_FEC_BUF_RS_BITS, | |
782 | 0, 0, NULL); | |
783 | if (!f->cache) { | |
784 | ti->error = "Cannot create FEC buffer cache"; | |
785 | return -ENOMEM; | |
786 | } | |
787 | ||
788 | /* Preallocate DM_VERITY_FEC_BUF_PREALLOC buffers for each thread */ | |
789 | f->prealloc_pool = mempool_create_slab_pool(num_online_cpus() * | |
790 | DM_VERITY_FEC_BUF_PREALLOC, | |
791 | f->cache); | |
792 | if (!f->prealloc_pool) { | |
793 | ti->error = "Cannot allocate FEC buffer prealloc pool"; | |
794 | return -ENOMEM; | |
795 | } | |
796 | ||
797 | f->extra_pool = mempool_create_slab_pool(0, f->cache); | |
798 | if (!f->extra_pool) { | |
799 | ti->error = "Cannot allocate FEC buffer extra pool"; | |
800 | return -ENOMEM; | |
801 | } | |
802 | ||
803 | /* Preallocate an output buffer for each thread */ | |
804 | f->output_pool = mempool_create_kmalloc_pool(num_online_cpus(), | |
805 | 1 << v->data_dev_block_bits); | |
806 | if (!f->output_pool) { | |
807 | ti->error = "Cannot allocate FEC output pool"; | |
808 | return -ENOMEM; | |
809 | } | |
810 | ||
811 | /* Reserve space for our per-bio data */ | |
30187e1d | 812 | ti->per_io_data_size += sizeof(struct dm_verity_fec_io); |
a739ff3f ST |
813 | |
814 | return 0; | |
815 | } |