• Milan Broz's avatar
    dm verity: fix FEC for RS roots unaligned to block size · df7b59ba
    Milan Broz authored
    Optional Forward Error Correction (FEC) code in dm-verity uses
    Reed-Solomon code and should support roots from 2 to 24.
    
    The error correction parity bytes (of roots lengths per RS block) are
    stored on a separate device in sequence without any padding.
    
    Currently, to access FEC device, the dm-verity-fec code uses dm-bufio
    client with block size set to verity data block (usually 4096 or 512
    bytes).
    
    Because this block size is not divisible by some (most!) of the roots
    supported lengths, data repair cannot work for partially stored parity
    bytes.
    
    This fix changes FEC device dm-bufio block size to "roots << SECTOR_SHIFT"
    where we can be sure that the full parity data is always available.
    (There cannot be partial FEC blocks because parity must cover whole
    sectors.)
    
    Because the optional FEC starting offset could be unaligned to this
    new block size, we have to use dm_bufio_set_sector_offset() to
    configure it.
    
    The problem is easily reproduced using veritysetup, e.g. for roots=13:
    
      # create verity device with RS FEC
      dd if=/dev/urandom of=data.img bs=4096 count=8 status=none
      veritysetup format data.img hash.img --fec-device=fec.img --fec-roots=13 | awk '/^Root hash/{ print $3 }' >roothash
    
      # create an erasure that should be always repairable with this roots setting
      dd if=/dev/zero of=data.img conv=notrunc bs=1 count=8 seek=4088 status=none
    
      # try to read it through dm-verity
      veritysetup open data.img test hash.img --fec-device=fec.img --fec-roots=13 $(cat roothash)
      dd if=/dev/mapper/test of=/dev/null bs=4096 status=noxfer
      # wait for possible recursive recovery in kernel
      udevadm settle
      veritysetup close test
    
    With this fix, errors are properly repaired.
      device-mapper: verity-fec: 7:1: FEC 0: corrected 8 errors
      ...
    
    Without it, FEC code usually ends on unrecoverable failure in RS decoder:
      device-mapper: verity-fec: 7:1: FEC 0: failed to correct: -74
      ...
    
    This problem is present in all kernels since the FEC code's
    introduction (kernel 4.5).
    
    It is thought that this problem is not visible in Android ecosystem
    because it always uses a default RS roots=2.
    
    Depends-on: a14e5ec6 ("dm bufio: subtract the number of initial sectors in dm_bufio_get_device_size")
    Signed-off-by: default avatarMilan Broz <gmazyland@gmail.com>
    Tested-by: default avatarJérôme Carretero <cJ-ko@zougloub.eu>
    Reviewed-by: default avatarSami Tolvanen <samitolvanen@google.com>
    Cc: stable@vger.kernel.org # 4.5+
    Signed-off-by: default avatarMike Snitzer <snitzer@redhat.com>
    df7b59ba
dm-verity-fec.c 20.4 KB