]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
4.19-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 8 Mar 2021 10:10:00 +0000 (11:10 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 8 Mar 2021 10:10:00 +0000 (11:10 +0100)
added patches:
dm-verity-fix-fec-for-rs-roots-unaligned-to-block-size.patch

queue-4.19/dm-verity-fix-fec-for-rs-roots-unaligned-to-block-size.patch [new file with mode: 0644]
queue-4.19/rsxx-return-efault-if-copy_to_user-fails.patch
queue-4.19/series

diff --git a/queue-4.19/dm-verity-fix-fec-for-rs-roots-unaligned-to-block-size.patch b/queue-4.19/dm-verity-fix-fec-for-rs-roots-unaligned-to-block-size.patch
new file mode 100644 (file)
index 0000000..7dad506
--- /dev/null
@@ -0,0 +1,143 @@
+From df7b59ba9245c4a3115ebaa905e3e5719a3810da Mon Sep 17 00:00:00 2001
+From: Milan Broz <gmazyland@gmail.com>
+Date: Tue, 23 Feb 2021 21:21:21 +0100
+Subject: dm verity: fix FEC for RS roots unaligned to block size
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Milan Broz <gmazyland@gmail.com>
+
+commit df7b59ba9245c4a3115ebaa905e3e5719a3810da upstream.
+
+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: a14e5ec66a7a ("dm bufio: subtract the number of initial sectors in dm_bufio_get_device_size")
+Signed-off-by: Milan Broz <gmazyland@gmail.com>
+Tested-by: Jérôme Carretero <cJ-ko@zougloub.eu>
+Reviewed-by: Sami Tolvanen <samitolvanen@google.com>
+Cc: stable@vger.kernel.org # 4.5+
+Signed-off-by: Mike Snitzer <snitzer@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/md/dm-verity-fec.c |   23 ++++++++++++-----------
+ 1 file changed, 12 insertions(+), 11 deletions(-)
+
+--- a/drivers/md/dm-verity-fec.c
++++ b/drivers/md/dm-verity-fec.c
+@@ -65,19 +65,18 @@ static int fec_decode_rs8(struct dm_veri
+ static u8 *fec_read_parity(struct dm_verity *v, u64 rsb, int index,
+                          unsigned *offset, struct dm_buffer **buf)
+ {
+-      u64 position, block;
++      u64 position, block, rem;
+       u8 *res;
+       position = (index + rsb) * v->fec->roots;
+-      block = position >> v->data_dev_block_bits;
+-      *offset = (unsigned)(position - (block << v->data_dev_block_bits));
++      block = div64_u64_rem(position, v->fec->roots << SECTOR_SHIFT, &rem);
++      *offset = (unsigned)rem;
+-      res = dm_bufio_read(v->fec->bufio, v->fec->start + block, buf);
++      res = dm_bufio_read(v->fec->bufio, block, buf);
+       if (unlikely(IS_ERR(res))) {
+               DMERR("%s: FEC %llu: parity read failed (block %llu): %ld",
+                     v->data_dev->name, (unsigned long long)rsb,
+-                    (unsigned long long)(v->fec->start + block),
+-                    PTR_ERR(res));
++                    (unsigned long long)block, PTR_ERR(res));
+               *buf = NULL;
+       }
+@@ -159,7 +158,7 @@ static int fec_decode_bufs(struct dm_ver
+               /* read the next block when we run out of parity bytes */
+               offset += v->fec->roots;
+-              if (offset >= 1 << v->data_dev_block_bits) {
++              if (offset >= v->fec->roots << SECTOR_SHIFT) {
+                       dm_bufio_release(buf);
+                       par = fec_read_parity(v, rsb, block_offset, &offset, &buf);
+@@ -675,7 +674,7 @@ int verity_fec_ctr(struct dm_verity *v)
+ {
+       struct dm_verity_fec *f = v->fec;
+       struct dm_target *ti = v->ti;
+-      u64 hash_blocks;
++      u64 hash_blocks, fec_blocks;
+       int ret;
+       if (!verity_fec_is_enabled(v)) {
+@@ -745,15 +744,17 @@ int verity_fec_ctr(struct dm_verity *v)
+       }
+       f->bufio = dm_bufio_client_create(f->dev->bdev,
+-                                        1 << v->data_dev_block_bits,
++                                        f->roots << SECTOR_SHIFT,
+                                         1, 0, NULL, NULL);
+       if (IS_ERR(f->bufio)) {
+               ti->error = "Cannot initialize FEC bufio client";
+               return PTR_ERR(f->bufio);
+       }
+-      if (dm_bufio_get_device_size(f->bufio) <
+-          ((f->start + f->rounds * f->roots) >> v->data_dev_block_bits)) {
++      dm_bufio_set_sector_offset(f->bufio, f->start << (v->data_dev_block_bits - SECTOR_SHIFT));
++
++      fec_blocks = div64_u64(f->rounds * f->roots, v->fec->roots << SECTOR_SHIFT);
++      if (dm_bufio_get_device_size(f->bufio) < fec_blocks) {
+               ti->error = "FEC device is too small";
+               return -E2BIG;
+       }
index 0ad7d572ecfd885998f3b2063ceb14fc8dceb926..0d5441f3ca628a41aeca2c2e84bf626b23e5b376 100644 (file)
@@ -17,14 +17,12 @@ Signed-off-by: Dan Carpenter <dan.carpenter@oracle.com>
 Signed-off-by: Jens Axboe <axboe@kernel.dk>
 Signed-off-by: Sasha Levin <sashal@kernel.org>
 ---
- drivers/block/rsxx/core.c | 8 +++++---
+ drivers/block/rsxx/core.c |    8 +++++---
  1 file changed, 5 insertions(+), 3 deletions(-)
 
-diff --git a/drivers/block/rsxx/core.c b/drivers/block/rsxx/core.c
-index 14056dc45064..d8ef8b16fb2e 100644
 --- a/drivers/block/rsxx/core.c
 +++ b/drivers/block/rsxx/core.c
-@@ -179,15 +179,17 @@ static ssize_t rsxx_cram_read(struct file *fp, char __user *ubuf,
+@@ -179,15 +179,17 @@ static ssize_t rsxx_cram_read(struct fil
  {
        struct rsxx_cardinfo *card = file_inode(fp)->i_private;
        char *buf;
@@ -45,6 +43,3 @@ index 14056dc45064..d8ef8b16fb2e 100644
        kfree(buf);
        if (st)
                return st;
--- 
-2.30.1
-
index 45f8c6ad3d17d60510e65a73f9de7ff665fe9ad2..bce4a7a449d37446e00161020a28d7391df31771 100644 (file)
@@ -16,3 +16,4 @@ virtio-blk-modernize-sysfs-attribute-creation.patch
 alsa-ctxfi-cthw20k2-fix-mask-on-conf-to-allow-4-bits.patch
 rdma-rxe-fix-missing-kconfig-dependency-on-crypto.patch
 rsxx-return-efault-if-copy_to_user-fails.patch
+dm-verity-fix-fec-for-rs-roots-unaligned-to-block-size.patch