mirror of
https://github.com/torvalds/linux.git
synced 2026-04-18 06:44:00 -04:00
It's hard to reconcile the value stored in dm_verity_fec::rounds with its name and documentation. Most likely "rounds" is being used as an alias for what is more commonly called the interleaving degree or "number of ways". But the interleaving is done at the byte level, whereas the units of "rounds" are blocks. So it's not really that. In practice, the reason the code needs this value is that it expresses the number of blocks in each "region" of the message data, where each region contains the bytes from a particular index in the RS codewords. Rename it to region_blocks to make the code a bit more understandable. Signed-off-by: Eric Biggers <ebiggers@kernel.org> Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
167 lines
4.7 KiB
C
167 lines
4.7 KiB
C
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
/*
|
|
* Copyright (C) 2015 Google, Inc.
|
|
*
|
|
* Author: Sami Tolvanen <samitolvanen@google.com>
|
|
*/
|
|
|
|
#ifndef DM_VERITY_FEC_H
|
|
#define DM_VERITY_FEC_H
|
|
|
|
#include "dm-verity.h"
|
|
#include <linux/rslib.h>
|
|
|
|
/* Reed-Solomon(n, k) parameters */
|
|
#define DM_VERITY_FEC_RS_N 255
|
|
#define DM_VERITY_FEC_MIN_ROOTS 2 /* RS(255, 253): ~0.8% space overhead */
|
|
#define DM_VERITY_FEC_MAX_ROOTS 24 /* RS(255, 231): ~10% space overhead */
|
|
|
|
/* buffers for deinterleaving and decoding */
|
|
#define DM_VERITY_FEC_BUF_RS_BITS 4 /* log2(RS messages per buffer) */
|
|
|
|
#define DM_VERITY_OPT_FEC_DEV "use_fec_from_device"
|
|
#define DM_VERITY_OPT_FEC_BLOCKS "fec_blocks"
|
|
#define DM_VERITY_OPT_FEC_START "fec_start"
|
|
#define DM_VERITY_OPT_FEC_ROOTS "fec_roots"
|
|
|
|
/* configuration */
|
|
struct dm_verity_fec {
|
|
struct dm_dev *dev; /* parity data device */
|
|
struct dm_bufio_client *data_bufio; /* for data dev access */
|
|
struct dm_bufio_client *bufio; /* for parity data access */
|
|
size_t block_size; /* size of data, hash, and parity blocks in bytes */
|
|
sector_t start; /* parity data start in blocks */
|
|
sector_t blocks; /* number of blocks covered */
|
|
sector_t region_blocks; /* blocks per region: ceil(blocks / rs_k) */
|
|
sector_t hash_blocks; /* blocks covered after v->hash_start */
|
|
unsigned char roots; /* parity bytes per RS codeword, n-k of RS(n, k) */
|
|
unsigned char rs_k; /* message bytes per RS codeword, k of RS(n, k) */
|
|
mempool_t fio_pool; /* mempool for dm_verity_fec_io */
|
|
mempool_t rs_pool; /* mempool for fio->rs */
|
|
mempool_t prealloc_pool; /* mempool for preallocated buffers */
|
|
mempool_t output_pool; /* mempool for output */
|
|
struct kmem_cache *cache; /* cache for buffers */
|
|
atomic64_t corrected; /* corrected errors */
|
|
};
|
|
|
|
/* per-bio data */
|
|
struct dm_verity_fec_io {
|
|
struct rs_control *rs; /* Reed-Solomon state */
|
|
int erasures[DM_VERITY_FEC_MAX_ROOTS + 1]; /* erasures for decode_rs8 */
|
|
u8 *output; /* buffer for corrected output */
|
|
unsigned int level; /* recursion level */
|
|
unsigned int nbufs; /* number of buffers allocated */
|
|
/*
|
|
* Buffers for deinterleaving RS codewords. Each buffer has space for
|
|
* the message bytes of (1 << DM_VERITY_FEC_BUF_RS_BITS) RS codewords.
|
|
* The array length is fec_max_nbufs(v), and we try to allocate that
|
|
* many buffers. However, in low-memory situations we may be unable to
|
|
* allocate all buffers. 'nbufs' holds the number actually allocated.
|
|
*/
|
|
u8 *bufs[];
|
|
};
|
|
|
|
#ifdef CONFIG_DM_VERITY_FEC
|
|
|
|
/* each feature parameter requires a value */
|
|
#define DM_VERITY_OPTS_FEC 8
|
|
|
|
/* Returns true if forward error correction is enabled. */
|
|
static inline bool verity_fec_is_enabled(struct dm_verity *v)
|
|
{
|
|
return v->fec && v->fec->dev;
|
|
}
|
|
|
|
extern int verity_fec_decode(struct dm_verity *v, struct dm_verity_io *io,
|
|
enum verity_block_type type, const u8 *want_digest,
|
|
sector_t block, u8 *dest);
|
|
|
|
extern unsigned int verity_fec_status_table(struct dm_verity *v, unsigned int sz,
|
|
char *result, unsigned int maxlen);
|
|
|
|
extern void __verity_fec_finish_io(struct dm_verity_io *io);
|
|
static inline void verity_fec_finish_io(struct dm_verity_io *io)
|
|
{
|
|
if (unlikely(io->fec_io))
|
|
__verity_fec_finish_io(io);
|
|
}
|
|
|
|
static inline void verity_fec_init_io(struct dm_verity_io *io)
|
|
{
|
|
io->fec_io = NULL;
|
|
}
|
|
|
|
extern bool verity_is_fec_opt_arg(const char *arg_name);
|
|
extern int verity_fec_parse_opt_args(struct dm_arg_set *as,
|
|
struct dm_verity *v, unsigned int *argc,
|
|
const char *arg_name);
|
|
|
|
extern void verity_fec_dtr(struct dm_verity *v);
|
|
|
|
extern int verity_fec_ctr_alloc(struct dm_verity *v);
|
|
extern int verity_fec_ctr(struct dm_verity *v);
|
|
|
|
#else /* !CONFIG_DM_VERITY_FEC */
|
|
|
|
#define DM_VERITY_OPTS_FEC 0
|
|
|
|
static inline bool verity_fec_is_enabled(struct dm_verity *v)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
static inline int verity_fec_decode(struct dm_verity *v,
|
|
struct dm_verity_io *io,
|
|
enum verity_block_type type,
|
|
const u8 *want_digest,
|
|
sector_t block, u8 *dest)
|
|
{
|
|
return -EOPNOTSUPP;
|
|
}
|
|
|
|
static inline unsigned int verity_fec_status_table(struct dm_verity *v,
|
|
unsigned int sz, char *result,
|
|
unsigned int maxlen)
|
|
{
|
|
return sz;
|
|
}
|
|
|
|
static inline void verity_fec_finish_io(struct dm_verity_io *io)
|
|
{
|
|
}
|
|
|
|
static inline void verity_fec_init_io(struct dm_verity_io *io)
|
|
{
|
|
}
|
|
|
|
static inline bool verity_is_fec_opt_arg(const char *arg_name)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
static inline int verity_fec_parse_opt_args(struct dm_arg_set *as,
|
|
struct dm_verity *v,
|
|
unsigned int *argc,
|
|
const char *arg_name)
|
|
{
|
|
return -EINVAL;
|
|
}
|
|
|
|
static inline void verity_fec_dtr(struct dm_verity *v)
|
|
{
|
|
}
|
|
|
|
static inline int verity_fec_ctr_alloc(struct dm_verity *v)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
static inline int verity_fec_ctr(struct dm_verity *v)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
#endif /* CONFIG_DM_VERITY_FEC */
|
|
|
|
#endif /* DM_VERITY_FEC_H */
|