Re: btrfs thinks fs is full, though 11GB should be still free

Andrei Borzenkov
2024-01-06T08:12:48Z

On 06.01.2024 08:40, Qu Wenruo wrote:
>
>
> On 2024/1/6 11:12, Christoph Anton Mitterer wrote:
>> On Fri, 2024-01-05 at 17:37 +1030, Qu Wenruo wrote:
>>> but pretty hard to find a
>>> good way to improve:
>>
>> I guess it would not be an alternative to do the work on truncate (i.e.
>> check whether a lot is wasted and if so, create a new extent with just
>> the right size), because that would need a full re-write of the
>> extent... or would it?
>
> I'm not sure if it's a valid idea to do all these on truncation.
> It would involve doing all the backref walk to determine if it's needed
> to do the COW.
>
>>
>> Also, a while ago in one of my mails I saw that:
>> $ cat affected-file > new-file
>> would also cause new-file to be affected... which I found pretty
>> strange.
>>
>> Any idea why that happens?
>
> Initially I thought that's impossible, until I tired it:
>
> mkfs.btrfs -f $dev1
> mount $dev1 $mnt
> xfs_io -f -c "pwrite 0 128m" $mnt/file
> sync
> truncate -s 4k $mnt/file
> sync
> cat $mnt/file > $mnt/new
> sync
>
> Then dump tree indeed show the new file is sharing the same large extent:
>
>
> item 6 key (257 INODE_ITEM 0) itemoff 15817 itemsize 160
> generation 7 transid 8 size 4096 nbytes 4096
> block group 0 mode 100600 links 1 uid 0 gid 0 rdev 0
> sequence 32770 flags 0x0(none)
> item 7 key (257 INODE_REF 256) itemoff 15803 itemsize 14
> index 2 namelen 4 name: file
> item 8 key (257 EXTENT_DATA 0) itemoff 15750 itemsize 53
> generation 7 type 1 (regular)
> extent data disk byte 298844160 nr 134217728 <<<
> extent data offset 0 nr 4096 ram 134217728
> extent compression 0 (none)
> item 9 key (258 INODE_ITEM 0) itemoff 15590 itemsize 160
> generation 9 transid 9 size 4096 nbytes 4096
> block group 0 mode 100644 links 1 uid 0 gid 0 rdev 0
> sequence 1 flags 0x0(none)
> item 10 key (258 INODE_REF 256) itemoff 15577 itemsize 13
> index 3 namelen 3 name: new
> item 11 key (258 EXTENT_DATA 0) itemoff 15524 itemsize 53
> generation 7 type 1 (regular)
> extent data disk byte 298844160 nr 134217728 <<<
> extent data offset 0 nr 4096 ram 134217728
> extent compression 0 (none)
>
> My guess is bash is doing something weird thus making the whole cat +
> redirection into reflink.
>

It is not bash (which just opens file and dup's it). It is cat from GNU
coreutils which defaults to using copy_file_range

10393 openat(AT_FDCWD, "/mnt/file", O_RDONLY) = 3
10393 fstat(3, {st_mode=S_IFREG|0644, st_size=4096, ...}) = 0
10393 fadvise64(3, 0, 0, POSIX_FADV_SEQUENTIAL) = 0
10393 uname({sysname="Linux", nodename="tw", ...}) = 0
10393 copy_file_range(3, NULL, 1, NULL, 9223372035781033984, 0) = 4096
10393 copy_file_range(3, NULL, 1, NULL, 9223372035781033984, 0) = 0

In case of btrfs this ends in btrfs_remap_file_range(). So it is more or
less self inflicted wound. May be btrfs should not reflink partial
extents in such cases.

> But at least dd works as expected by creating a new extent.
>
>>
>>
>>
>>> My previous guess is totally wrong, it has nothing to do with
>>> NODATACOW/PREALLOC flags at all.
>>>
>>> It's a defrag only problem.
>>
>> Sure, but I meant, if a file is NODATACOW and would be prealloced to a
>> large size and then truncated - would it also loose the extra space?
>
> That would be the same.
>
>>
>>
>> And do you think that other CoW fs would be affected, too? IIRC XFS is
>> also about to get CoW features... so may it's simply an IO pattern that
>> developers need to avoid with modern filesystems.
>
> Not sure, maybe XFS would do extra extent split to solve the problem.
>
> Thanks,
> Qu
>
>>
>>
>> Cheers,
>> Chris-
>>
>