Possible bug in BTRFS w/ Duplication

Sam Winchenbach swichenbach at tethers.com
Tue Jan 3 14:36:58 CET 2023


That is correct. This bug is present on a single device with duplication enabled. 

Here, in __btrfs_map_block the read length can be reduced to the stripe length when duplication is enabled.

	if (map->type & (BTRFS_BLOCK_GROUP_RAID0 | BTRFS_BLOCK_GROUP_RAID1 |
			 BTRFS_BLOCK_GROUP_RAID1C3 | BTRFS_BLOCK_GROUP_RAID1C4 |
			 BTRFS_BLOCK_GROUP_RAID5 | BTRFS_BLOCK_GROUP_RAID6 |
			 BTRFS_BLOCK_GROUP_RAID10 |
			 BTRFS_BLOCK_GROUP_DUP)) {
		/* we limit the length of each bio to what fits in a stripe */
		*length = min_t(u64, ce->size - offset,
			      map->stripe_len - stripe_offset);
	} else {
		*length = ce->size - offset;
	}

read_extent_data fails to read the complete length. I implemented a patch similar to yours and it worked perfectly.  I am a little sad you beat me to submitting it.


Thanks,
Sam Winchenbach

-----Original Message-----
From: Qu Wenruo <quwenruo.btrfs at gmx.com> 
Sent: Friday, December 30, 2022 7:10 PM
To: Sam Winchenbach <swichenbach at tethers.com>; Heinrich Schuchardt <xypron.glpk at gmx.de>; Marek Behún <kabel at kernel.org>
Cc: u-boot at lists.denx.de; Qu Wenruo <wqu at suse.com>; linux-btrfs at vger.kernel.org
Subject: Re: Possible bug in BTRFS w/ Duplication



On 2022/12/30 23:28, Sam Winchenbach wrote:
> I believe you fixed the issue with the patch you presented. I was in the process of testing a similar fix for release and it solved the issue I encountered.

But I still want to make sure that only RAID0 on single device can cause the problem.

For multi-device RAID0/RAID10/RAID5/6, we don't support them until we can scan all devices in U-boot...

Thanks,
Qu
> 
> Thanks,
> Sam Winchenbach
> 
> -----Original Message-----
> From: U-Boot <u-boot-bounces at lists.denx.de> On Behalf Of Qu Wenruo
> Sent: Thursday, December 29, 2022 7:01 PM
> To: Heinrich Schuchardt <xypron.glpk at gmx.de>; Sam Winchenbach 
> <swichenbach at tethers.com>; Marek Behún <kabel at kernel.org>
> Cc: u-boot at lists.denx.de; Qu Wenruo <wqu at suse.com>; 
> linux-btrfs at vger.kernel.org
> Subject: Re: Possible bug in BTRFS w/ Duplication
> 
> 
> 
> On 2022/12/29 22:12, Heinrich Schuchardt wrote:
>> On 12/28/22 21:51, Sam Winchenbach wrote:
>>> Hello,
>>>
>>> Hello, I have hit the following situation when trying to load files 
>>> from a BTRFS partition with duplication enabled.
> 
> You mean multi-device?
> 
> For DUP/RAID1 duplication, they don't have stripe limitation at all.
> 
> Thus I believe you're talking about RAID0 (which doesn't have any duplication/extra mirrors) or RAID10 or RAID5/6?
> 
> But for now, we don't support multi-device in U-boot yet, thus I'm not sure what situation you're talking about.
> 
> Mind to run the following command?
> 
>    # btrfs fi usage <mnt of the btrfs>
> 
>>>
>>> In the first example I read a 16KiB file - __btrfs_map_block() 
>>> changes the length to something larger than the file being read. 
>>> This works fine, as length is later clamped to the file size.
>>>
>>> In the second example, __btrfs_map_block() changes the length 
>>> parameter to something smaller than the file (the size of a stripe).
>>> This seems to break this check here:
>>>
>>>       read = len;
>>>       num_copies = btrfs_num_copies(fs_info, logical, len);
>>>       for (i = 1; i <= num_copies; i++) {
>>>           ret = read_extent_data(fs_info, dest, logical, &read, i);
>>>           if (ret < 0 || read != len) {
>>>               continue;
>>>           }
>>>           finished = true;
>>>           break;
>>>       }
>>>
>>> The problem being that read is always less than len.
>>>
>>> I am not sure if __btrfs_map_block is changing "len" to the 
>>> incorrect value, or if there is some logic in "read_extent_data" 
>>> that isn't correct. Any pointers on how this code is supposed to 
>>> work would be greatly appreciated.
>>> Thanks.
>>
>> Thanks for reporting the issue
>>
>> $ scripts/get_maintainer.pl -f fs/btrfs/volumes.c
>>
>> suggests to include
>>
>> "Marek Behún" <kabel at kernel.org> (maintainer:BTRFS) Qu Wenruo 
>> <wqu at suse.com> (reviewer:BTRFS) linux-btrfs at vger.kernel.org
>>
>> to the communication.
>>
>> Best regards
>>
>> Heinrich
>>
>>>
>>> === EXAMPLE 2 ===
>>> Zynq> load mmc 1:0 0 16K
>>> [btrfs_file_read,fs/btrfs/inode.c:710] === read the aligned part === 
>>> [btrfs_read_extent_reg,fs/btrfs/inode.c:458] before read_extent_data 
>>> (ret = 0, read = 16384, len = 16384) 
>>> [read_extent_data,fs/btrfs/disk-io.c:547] before __btrfs_map_block 
>>> (len = 16384) [read_extent_data,fs/btrfs/disk-io.c:550] after 
>>> __btrfs_map_block (len = 28672) 
>>> [read_extent_data,fs/btrfs/disk-io.c:565] before __btrfs_devread 
>>> (len = 16384) [read_extent_data,fs/btrfs/disk-io.c:568] after 
>>> __btrfs_devread (len =
>>> 16384)
>>> [btrfs_read_extent_reg,fs/btrfs/inode.c:460] after read_extent_data 
>>> (ret = 0, read = 16384, len = 16384)
>>> cur: 0, extent_num_bytes: 16384, aligned_end: 16384
>>> 16384 bytes read in 100 ms (159.2 KiB/s)
>>>
>>> === EXAMPLE 2 ===
>>> Zynq> load mmc 1:0 0 32K
>>> [btrfs_file_read,fs/btrfs/inode.c:710] === read the aligned part === 
>>> [btrfs_read_extent_reg,fs/btrfs/inode.c:458] before read_extent_data 
>>> (ret = 0, read = 32768, len = 32768) 
>>> [read_extent_data,fs/btrfs/disk-io.c:547] before __btrfs_map_block 
>>> (len = 32768) [read_extent_data,fs/btrfs/disk-io.c:550] after 
>>> __btrfs_map_block (len = 12288) 
>>> [read_extent_data,fs/btrfs/disk-io.c:565] before __btrfs_devread 
>>> (len = 12288) [read_extent_data,fs/btrfs/disk-io.c:568] after 
>>> __btrfs_devread (len =
>>> 12288)
> 
> So the first 3 sectors are before the stripe boundary and we read it correctly.
> 
>>> [btrfs_read_extent_reg,fs/btrfs/inode.c:460] after read_extent_data 
>>> (ret = 0, read = 12288, len = 32768) 
>>> [btrfs_read_extent_reg,fs/btrfs/inode.c:458] before read_extent_data 
>>> (ret = 0, read = 12288, len = 32768) 
>>> [read_extent_data,fs/btrfs/disk-io.c:547] before __btrfs_map_block 
>>> (len = 12288) [read_extent_data,fs/btrfs/disk-io.c:550] after 
>>> __btrfs_map_block (len = 12288)
> 
> I believe this is the problem.
> 
> If we're reading the full 32K, and the first 12K is in the first stripe, we should then try to map the remaining 20K, not the 12K again.
> 
> I'll look into the situation.
> But if you can provide the image or the dump, it can greatly help the debugging.
> 
> Thanks,
> Qu
> 
>>> [read_extent_data,fs/btrfs/disk-io.c:565] before __btrfs_devread 
>>> (len = 12288) [read_extent_data,fs/btrfs/disk-io.c:568] after 
>>> __btrfs_devread (len =
>>> 12288)
>>> [btrfs_read_extent_reg,fs/btrfs/inode.c:460] after read_extent_data 
>>> (ret = 0, read = 12288, len = 32768)
>>> file: fs/btrfs/inode.c, line: 468
>>> cur: 0, extent_num_bytes: 32768, aligned_end: 32768
>>> -----> btrfs_read_extent_reg: -5, line: 758
>>> BTRFS: An error occurred while reading file 32K Failed to load '32K'
>>>
>>>
>>>
>>>
>>>
>>> Sam Winchenbach
>>> Embedded Software Engineer III
>>> Tethers Unlimited, Inc. | Connect Your Universe | www.tethers.com 
>>> swinchenbach at tethers.com | C: 207-974-6934
>>> 11711 North Creek Pkwy # D113, Bothell, WA 98011-8808, USA
>>


More information about the U-Boot mailing list