diff mbox series

btrfs: fix RAID direct I/O reads with alternate csums

Message ID b88c888c800d66ad39b4a561ec6601d2db59529e.1583186403.git.osandov@fb.com (mailing list archive)
State New, archived
Headers show
Series btrfs: fix RAID direct I/O reads with alternate csums | expand

Commit Message

Omar Sandoval March 2, 2020, 10:02 p.m. UTC
From: Omar Sandoval <osandov@fb.com>

btrfs_lookup_and_bind_dio_csum() does pointer arithmetic which assumes
32-bit checksums. If using a larger checksum, this leads to spurious
failures when a direct I/O read crosses a stripe. This is easy
to reproduce:

  # mkfs.btrfs -f --checksum BLAKE2b -d raid0 /dev/vdc /dev/vdd
  ...
  # mount /dev/vdc /mnt
  # cd /mnt
  # dd if=/dev/urandom of=foo bs=1M count=1 status=none
  # dd if=foo of=/dev/null bs=1M iflag=direct status=none
  dd: error reading 'foo': Input/output error
  # dmesg | tail -1
  [  135.821568] BTRFS warning (device vdc): csum failed root 5 ino 257 off 421888 ...

Fix it by using the actual checksum size.

Fixes: 1e25a2e3ca0d ("btrfs: don't assume ordered sums to be 4 bytes")
Signed-off-by: Omar Sandoval <osandov@fb.com>
---
I wasn't sure what commit to point at for the fixes tag (or whether to
just add a stable tag).

Based on misc-next. xfstest to follow.

Thanks,
Omar

 fs/btrfs/inode.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

Comments

Johannes Thumshirn March 3, 2020, 10:42 a.m. UTC | #1
Good catch,
Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
David Sterba March 3, 2020, 2:25 p.m. UTC | #2
On Mon, Mar 02, 2020 at 02:02:49PM -0800, Omar Sandoval wrote:
> From: Omar Sandoval <osandov@fb.com>
> 
> btrfs_lookup_and_bind_dio_csum() does pointer arithmetic which assumes
> 32-bit checksums. If using a larger checksum, this leads to spurious
> failures when a direct I/O read crosses a stripe. This is easy
> to reproduce:
> 
>   # mkfs.btrfs -f --checksum BLAKE2b -d raid0 /dev/vdc /dev/vdd
>   ...
>   # mount /dev/vdc /mnt
>   # cd /mnt
>   # dd if=/dev/urandom of=foo bs=1M count=1 status=none
>   # dd if=foo of=/dev/null bs=1M iflag=direct status=none
>   dd: error reading 'foo': Input/output error
>   # dmesg | tail -1
>   [  135.821568] BTRFS warning (device vdc): csum failed root 5 ino 257 off 421888 ...
> 
> Fix it by using the actual checksum size.
> 
> Fixes: 1e25a2e3ca0d ("btrfs: don't assume ordered sums to be 4 bytes")
> Signed-off-by: Omar Sandoval <osandov@fb.com>
> ---
> I wasn't sure what commit to point at for the fixes tag (or whether to
> just add a stable tag).

That one is fine, added to the rc queue so we can get it to stable soon.
Thanks.
diff mbox series

Patch

diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index dacfd17a3121..8a3bc19d83ff 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -7840,6 +7840,7 @@  static inline blk_status_t btrfs_lookup_and_bind_dio_csum(struct inode *inode,
 {
 	struct btrfs_io_bio *io_bio = btrfs_io_bio(bio);
 	struct btrfs_io_bio *orig_io_bio = btrfs_io_bio(dip->orig_bio);
+	u16 csum_size;
 	blk_status_t ret;
 
 	/*
@@ -7859,7 +7860,8 @@  static inline blk_status_t btrfs_lookup_and_bind_dio_csum(struct inode *inode,
 
 	file_offset -= dip->logical_offset;
 	file_offset >>= inode->i_sb->s_blocksize_bits;
-	io_bio->csum = (u8 *)(((u32 *)orig_io_bio->csum) + file_offset);
+	csum_size = btrfs_super_csum_size(btrfs_sb(inode->i_sb)->super_copy);
+	io_bio->csum = orig_io_bio->csum + csum_size * file_offset;
 
 	return 0;
 }