Commit ca0da6cc authored by Eric Biggers's avatar Eric Biggers Committed by Mikulas Patocka
Browse files

dm-verity-fec: move computation of offset and rsb down a level



verity_fec_decode() computes (offset, rsb) from the target block index
and calls fec_decode_rsb() with these parameters.  Move this computation
into fec_decode_rsb(), and rename fec_decode_rsb() to fec_decode().

This ends up being simpler and enables further refactoring, specifically
making use of the quotient from the division more easily.  The function
renaming also eliminates a reference to the ambiguous term "rsb".

This change does mean the same div64_u64_rem() can now be executed twice
per block, since verity_fec_decode() calls fec_decode() up to twice per
block.  However, this cost is negligible compared to the rest of FEC.

Signed-off-by: default avatarEric Biggers <ebiggers@kernel.org>
Signed-off-by: default avatarMikulas Patocka <mpatocka@redhat.com>
parent 3ad2b952
Loading
Loading
Loading
Loading
+18 −28
Original line number Diff line number Diff line
@@ -306,16 +306,26 @@ static void fec_init_bufs(struct dm_verity *v, struct dm_verity_fec_io *fio)
}

/*
 * Decode all RS blocks in a single data block and return the target block
 * (indicated by @offset) in fio->output. If @use_erasures is non-zero, uses
 * hashes to locate erasures.
 * Try to correct the message (data or hash) block at index @target_block.
 *
 * If @use_erasures is true, use verity hashes to locate erasures.  This makes
 * the error correction slower but up to twice as capable.
 *
 * On success, return 0 and write the corrected block to @fio->output.  0 is
 * returned only if the digest of the corrected block matches @want_digest; this
 * is critical to ensure that FEC can't cause dm-verity to return bad data.
 */
static int fec_decode_rsb(struct dm_verity *v, struct dm_verity_io *io,
			  struct dm_verity_fec_io *fio, u64 rsb, u64 offset,
static int fec_decode(struct dm_verity *v, struct dm_verity_io *io,
		      struct dm_verity_fec_io *fio, u64 target_block,
		      const u8 *want_digest, bool use_erasures)
{
	int r, neras = 0;
	unsigned int out_pos;
	u64 offset = target_block << v->data_dev_block_bits;
	u64 rsb;

	div64_u64_rem(offset, v->fec->region_blocks << v->data_dev_block_bits,
		      &rsb);

	for (out_pos = 0; out_pos < v->fec->block_size;) {
		fec_init_bufs(v, fio);
@@ -353,7 +363,6 @@ int verity_fec_decode(struct dm_verity *v, struct dm_verity_io *io,
{
	int r;
	struct dm_verity_fec_io *fio;
	u64 offset, rsb;

	if (!verity_fec_is_enabled(v))
		return -EOPNOTSUPP;
@@ -370,33 +379,14 @@ int verity_fec_decode(struct dm_verity *v, struct dm_verity_io *io,
	if (type == DM_VERITY_BLOCK_TYPE_METADATA)
		block = block - v->hash_start + v->data_blocks;

	/*
	 * For RS(n, k), the continuous FEC data is divided into blocks of k
	 * bytes. Since block size may not be divisible by k, the last block
	 * is zero padded when decoding.
	 *
	 * Each byte of the block is covered by a different RS(n, k) code,
	 * and each code is interleaved over k blocks to make it less likely
	 * that bursty corruption will leave us in unrecoverable state.
	 */

	offset = block << v->data_dev_block_bits;

	/*
	 * The base RS block we can feed to the interleaver to find out all
	 * blocks required for decoding.
	 */
	div64_u64_rem(offset, v->fec->region_blocks << v->data_dev_block_bits,
		      &rsb);

	/*
	 * Locating erasures is slow, so attempt to recover the block without
	 * them first. Do a second attempt with erasures if the corruption is
	 * bad enough.
	 */
	r = fec_decode_rsb(v, io, fio, rsb, offset, want_digest, false);
	r = fec_decode(v, io, fio, block, want_digest, false);
	if (r < 0) {
		r = fec_decode_rsb(v, io, fio, rsb, offset, want_digest, true);
		r = fec_decode(v, io, fio, block, want_digest, true);
		if (r < 0)
			goto done;
	}