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: Eric Biggers <[email protected]>
---
 drivers/md/dm-verity-fec.c | 46 +++++++++++++++-----------------------
 1 file changed, 18 insertions(+), 28 deletions(-)

diff --git a/drivers/md/dm-verity-fec.c b/drivers/md/dm-verity-fec.c
index 51263f2be1350..91670f7d0ea16 100644
--- a/drivers/md/dm-verity-fec.c
+++ b/drivers/md/dm-verity-fec.c
@@ -304,20 +304,30 @@ static void fec_init_bufs(struct dm_verity *v, struct 
dm_verity_fec_io *fio)
 
        memset(fio->erasures, 0, sizeof(fio->erasures));
 }
 
 /*
- * 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,
-                         const u8 *want_digest, bool use_erasures)
+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);
 
                r = fec_read_bufs(v, io, rsb, offset, out_pos,
@@ -351,11 +361,10 @@ 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)
 {
        int r;
        struct dm_verity_fec_io *fio;
-       u64 offset, rsb;
 
        if (!verity_fec_is_enabled(v))
                return -EOPNOTSUPP;
 
        fio = io->fec_io;
@@ -368,37 +377,18 @@ int verity_fec_decode(struct dm_verity *v, struct 
dm_verity_io *io,
        fio->level++;
 
        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;
        }
 
        memcpy(dest, fio->output, v->fec->block_size);
-- 
2.52.0


Reply via email to