[PATCH U-BOOT v2] btrfs: fix offset when reading compressed extents
Qu Wenruo
wqu at suse.com
Tue Apr 18 09:20:16 CEST 2023
On 2023/4/18 14:41, Dominique Martinet wrote:
> From: Dominique Martinet <dominique.martinet at atmark-techno.com>
>
> btrfs_read_extent_reg correctly computed the extent offset in the
> BTRFS_COMPRESS_NONE case, but did not account for the 'offset - key.offset'
> part correctly in the compressed case, making the function read
> incorrect data.
>
> In the case I examined, the last 4k of a file was corrupted and
> contained data from a few blocks prior, e.g. reading a 10k file with a
> single extent:
> btrfs_file_read()
> -> btrfs_read_extent_reg
> (aligned part loop, until 8k)
> -> read_and_truncate_page
> -> btrfs_read_extent_reg
> (re-reads the last extent from 8k to the end,
> incorrectly reading the first 2k of data)
>
> This can be reproduced as follow:
> $ truncate -s 200M btr
> $ mount btr -o compress /mnt
> $ pat() { dd if=/dev/zero bs=1M count=$1 iflag=count_bytes status=none | tr '\0' "\\$2"; }
> $ { pat 4K 1; pat 4K 2; pat 2K 3; } > /mnt/file
> $ sync
> $ filefrag -v /mnt/file
> File size of /mnt/file is 10240 (3 blocks of 4096 bytes)
> ext: logical_offset: physical_offset: length: expected: flags:
> 0: 0.. 2: 3328.. 3330: 3: last,encoded,eof
> $ umount /mnt
>
> Then in u-boot:
> => load scsi 0 2000000 file
> 10240 bytes read in 3 ms (3.3 MiB/s)
> => md 2001ff0
> 02001ff0: 02020202 02020202 02020202 02020202 ................
> 02002000: 01010101 01010101 01010101 01010101 ................
> 02002010: 01010101 01010101 01010101 01010101 ................
>
> (02002000 onwards should contain '03' pattern but went back to 01,
> start of the extent)
>
> After patch, data is read properly:
> => md 2001ff0
> 02001ff0: 02020202 02020202 02020202 02020202 ................
> 02002000: 03030303 03030303 03030303 03030303 ................
> 02002010: 03030303 03030303 03030303 03030303 ................
>
> Note that the code previously (before commit e3427184f38a ("fs: btrfs:
> Implement btrfs_file_read()")) did not split that read in two, so
> this is a regression even if the previous code might not have been
> handling offsets correctly either (something that booted now fails to
> boot)
>
> Fixes: a26a6bedafcf ("fs: btrfs: Introduce btrfs_read_extent_inline() and btrfs_read_extent_reg()")
> Signed-off-by: Dominique Martinet <dominique.martinet at atmark-techno.com>
Reviewed-by: Qu Wenruo <wqu at suse.com>
Thanks,
Qu
> ---
> Changes in v2:
> - Keep offset decomposition explicit where it is used
> - Add reproducer/clarify explanation in commit message
> - Drop other patches temporarily
> - Link to v1: https://lore.kernel.org/r/20230418-btrfs-extent-reads-v1-0-47ba9839f0cc@codewreck.org
> ---
> fs/btrfs/inode.c | 4 +++-
> 1 file changed, 3 insertions(+), 1 deletion(-)
>
> diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
> index 40025662f250..38e285bf94b0 100644
> --- a/fs/btrfs/inode.c
> +++ b/fs/btrfs/inode.c
> @@ -511,7 +511,9 @@ int btrfs_read_extent_reg(struct btrfs_path *path,
> if (ret < dsize)
> memset(dbuf + ret, 0, dsize - ret);
> /* Then copy the needed part */
> - memcpy(dest, dbuf + btrfs_file_extent_offset(leaf, fi), len);
> + memcpy(dest,
> + dbuf + btrfs_file_extent_offset(leaf, fi) + offset - key.offset,
> + len);
> ret = len;
> out:
> free(cbuf);
>
> ---
> base-commit: 5db4972a5bbdbf9e3af48ffc9bc4fec73b7b6a79
> change-id: 20230418-btrfs-extent-reads-e2df6e329ad4
>
> Best regards,
More information about the U-Boot
mailing list