drivers/md/dm-verity-fec.c

Source file repositories/reference/linux-study-clean/drivers/md/dm-verity-fec.c

File Facts

System
Linux kernel
Corpus path
drivers/md/dm-verity-fec.c
Extension
.c
Size
20865 bytes
Lines
735
Domain
Driver Families
Bucket
drivers/md
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

if (to_copy < v->fec->roots) {
			parity_block++;
			parity_pos = 0;

			dm_bufio_release(buf);
			par = dm_bufio_read_with_ioprio(v->fec->bufio,
							parity_block, &buf,
							bio->bi_ioprio);
			if (IS_ERR(par)) {
				DMERR("%s: FEC %llu: parity read failed (block %llu): %ld",
				      v->data_dev->name, target_block,
				      parity_block, PTR_ERR(par));
				return PTR_ERR(par);
			}
			for (; j < v->fec->roots; j++)
				par_buf[j] = par[parity_pos++];
		}

		/* Decode an RS codeword using the Reed-Solomon library. */
		res = decode_rs8(fio->rs, msg_buf, par_buf, v->fec->rs_k,
				 NULL, neras, fio->erasures, 0, NULL);
		if (res < 0) {
			r = res;
			goto done;
		}
		corrected += res;
		fio->output[out_pos++] = msg_buf[target_region];

		if (out_pos >= v->fec->block_size)
			goto done;
	}
done:
	dm_bufio_release(buf);

	if (r < 0 && neras)
		DMERR_LIMIT("%s: FEC %llu: failed to correct: %d",
			    v->data_dev->name, target_block, r);
	else if (r == 0)
		DMWARN_LIMIT("%s: FEC %llu: corrected %d errors",
			     v->data_dev->name, target_block, corrected);

	return r;
}

/*
 * Locate data block erasures using verity hashes.
 */
static int fec_is_erasure(struct dm_verity *v, struct dm_verity_io *io,
			  const u8 *want_digest, const u8 *data)
{
	if (unlikely(verity_hash(v, io, data, v->fec->block_size,
				 io->tmp_digest)))
		return 0;

	return memcmp(io->tmp_digest, want_digest, v->digest_size) != 0;
}

/*
 * Read the message block at index @index_in_region within each of the
 * @v->fec->rs_k regions and deinterleave their contents into @io->fec_io->bufs.
 *
 * @target_block gives the index of specific block within this sequence that is
 * being corrected, relative to the start of all the FEC message blocks.
 *
 * @out_pos gives the current output position, i.e. the position in (each) block
 * from which to start the deinterleaving.  Deinterleaving continues until
 * either end-of-block is reached or there's no more buffer space.
 *
 * If @neras is non-NULL, then also use verity hashes and the presence/absence
 * of I/O errors to determine which of the message blocks in the sequence are
 * likely to be incorrect.  Write the number of such blocks to *@neras and the
 * indices of the corresponding RS message bytes in [0, k - 1] to
 * @io->fec_io->erasures, up to a limit of @v->fec->roots + 1 such blocks.
 */
static int fec_read_bufs(struct dm_verity *v, struct dm_verity_io *io,
			 u64 target_block, u64 index_in_region,
			 unsigned int out_pos, int *neras)
{
	bool is_zero;
	int i, j;
	struct dm_buffer *buf;
	struct dm_bufio_client *bufio;
	struct dm_verity_fec_io *fio = io->fec_io;
	u64 block;
	u8 *bbuf;
	u8 want_digest[HASH_MAX_DIGESTSIZE];
	unsigned int n, src_pos;
	struct bio *bio = dm_bio_from_per_bio_data(io, v->ti->per_io_data_size);

	if (neras)

Annotation

Implementation Notes